Skip to content

Commit 6f2c404

Browse files
committed
subscription page
1 parent 9f046a1 commit 6f2c404

File tree

18 files changed

+1193
-13
lines changed

18 files changed

+1193
-13
lines changed
64.8 KB
Binary file not shown.

src/components/actionbar/ComfyActionbar.vue

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
)
3535
"
3636
/>
37-
<ComfyQueueButton />
37+
<SubscribeToRun v-if="!activeSubscription" />
38+
<ComfyQueueButton v-else />
3839
</div>
3940
</Panel>
4041
</div>
@@ -49,14 +50,48 @@ import {
4950
} from '@vueuse/core'
5051
import { clamp } from 'es-toolkit/compat'
5152
import Panel from 'primevue/panel'
52-
import { computed, nextTick, onMounted, ref, watch } from 'vue'
53-
53+
import type { Component } from 'vue'
54+
import {
55+
computed,
56+
defineAsyncComponent,
57+
nextTick,
58+
onMounted,
59+
ref,
60+
watch
61+
} from 'vue'
62+
63+
import { isCloud } from '@/platform/distribution/types'
5464
import { t } from '@/i18n'
5565
import { useSettingStore } from '@/platform/settings/settingStore'
5666
import { cn } from '@/utils/tailwindUtil'
5767
5868
import ComfyQueueButton from './ComfyQueueButton.vue'
5969
70+
const activeSubscription = ref(false)
71+
const SubscribeToRun: Component | null = isCloud
72+
? defineAsyncComponent(
73+
() =>
74+
import(
75+
'../../platform/cloud/subscription/components/SubscribeToRun.vue'
76+
)
77+
)
78+
: null
79+
80+
if (isCloud) {
81+
void import('@/platform/cloud/subscription/composables/useSubscription').then(
82+
({ useSubscription }) => {
83+
const { isActiveSubscription } = useSubscription()
84+
watch(
85+
isActiveSubscription,
86+
(value) => {
87+
activeSubscription.value = value
88+
},
89+
{ immediate: true }
90+
)
91+
}
92+
)
93+
}
94+
6095
const settingsStore = useSettingStore()
6196
6297
const position = computed(() => settingsStore.get('Comfy.UseNewMenu'))
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
@@ -157,6 +157,7 @@ export const useFirebaseAuthActions = () => {
157157
signUpWithEmail,
158158
updatePassword,
159159
deleteAccount,
160-
accessError
160+
accessError,
161+
reportError
161162
}
162163
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { watch } from 'vue'
2+
3+
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
4+
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
5+
import { isCloud } from '@/platform/distribution/types'
6+
import { useExtensionService } from '@/services/extensionService'
7+
8+
useExtensionService().registerExtension({
9+
name: 'Comfy.CloudSubscription',
10+
11+
setup: isCloud
12+
? async () => {
13+
const { isLoggedIn } = useCurrentUser()
14+
const { requireActiveSubscription } = useSubscription()
15+
16+
const checkSubscriptionStatus = () => {
17+
if (!isLoggedIn.value) return
18+
19+
void requireActiveSubscription()
20+
}
21+
22+
watch(() => isLoggedIn.value, checkSubscriptionStatus, {
23+
immediate: true
24+
})
25+
}
26+
: undefined
27+
})

src/extensions/core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ import './widgetInputs'
2626

2727
if (isCloud) {
2828
import('./cloudBadge')
29+
import('./cloudSubscription')
2930
}

src/locales/en/main.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,8 @@
17741774
"failedToInitiateCreditPurchase": "Failed to initiate credit purchase: {error}",
17751775
"failedToAccessBillingPortal": "Failed to access billing portal: {error}",
17761776
"failedToPurchaseCredits": "Failed to purchase credits: {error}",
1777+
"failedToFetchSubscription": "Failed to fetch subscription status: {error}",
1778+
"failedToInitiateSubscription": "Failed to initiate subscription: {error}",
17771779
"unauthorizedDomain": "Your domain {domain} is not authorized to use this service. Please contact {email} to add your domain to the whitelist.",
17781780
"useApiKeyTip": "Tip: Can't access normal login? Use the Comfy API Key option.",
17791781
"nothingSelected": "Nothing selected",
@@ -1914,6 +1916,34 @@
19141916
"added": "Added",
19151917
"accountInitialized": "Account initialized"
19161918
},
1919+
"subscription": {
1920+
"title": "Subscription",
1921+
"comfyCloud": "Comfy Cloud",
1922+
"beta": "BETA",
1923+
"perMonth": "USD / month",
1924+
"renewsDate": "Renews {date}",
1925+
"manageSubscription": "Manage subscription",
1926+
"apiNodesBalance": "\"API Nodes\" Credit Balance",
1927+
"apiNodesDescription": "For running commercial/proprietary models",
1928+
"totalCredits": "Total credits",
1929+
"viewUsageHistory": "View usage history",
1930+
"addApiCredits": "Add API credits",
1931+
"yourPlanIncludes": "Your plan includes:",
1932+
"viewMoreDetails": "View more details",
1933+
"learnMore": "Learn more",
1934+
"messageSupport": "Message support",
1935+
"invoiceHistory": "Invoice history",
1936+
"benefits": {
1937+
"benefit1": "$10 in monthly credits for API models — top up when needed",
1938+
"benefit2": "Up to 30 min runtime per job"
1939+
},
1940+
"required": {
1941+
"title": "Subscribe to",
1942+
"waitingForSubscription": "Complete your subscription in the new tab. We'll automatically detect when you're done!",
1943+
"subscribe": "Subscribe"
1944+
},
1945+
"subscribeToRun": "Subscribe to Run"
1946+
},
19171947
"userSettings": {
19181948
"title": "User Settings",
19191949
"name": "Name",
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<template>
2+
<Button
3+
v-tooltip.bottom="{
4+
value: $t('subscription.subscribeToRun'),
5+
showDelay: 600
6+
}"
7+
class="subscribe-to-run-button"
8+
:label="$t('subscription.subscribeToRun')"
9+
icon="pi pi-lock"
10+
severity="primary"
11+
size="small"
12+
data-testid="subscribe-to-run-button"
13+
@click="showSubscriptionDialog"
14+
/>
15+
</template>
16+
17+
<script setup lang="ts">
18+
import Button from 'primevue/button'
19+
20+
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
21+
22+
const { showSubscriptionDialog } = useSubscription()
23+
</script>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<template>
2+
<div class="flex flex-col gap-3">
3+
<div class="flex items-start gap-2">
4+
<i class="pi pi-check mt-1 text-sm" />
5+
<span class="text-sm">
6+
{{ $t('subscription.benefits.benefit1') }}
7+
</span>
8+
</div>
9+
10+
<div class="flex items-start gap-2">
11+
<i class="pi pi-check mt-1 text-sm" />
12+
<span class="text-sm">
13+
{{ $t('subscription.benefits.benefit2') }}
14+
</span>
15+
</div>
16+
17+
<Button
18+
:label="$t('subscription.viewMoreDetails')"
19+
text
20+
icon="pi pi-external-link"
21+
icon-pos="left"
22+
size="small"
23+
class="self-start !p-0 text-sm hover:!bg-transparent [&]:!text-[inherit]"
24+
@click="handleViewMoreDetails"
25+
/>
26+
</div>
27+
</template>
28+
29+
<script setup lang="ts">
30+
import Button from 'primevue/button'
31+
32+
const handleViewMoreDetails = () => {
33+
window.open('https://www.comfy.org/cloud', '_blank')
34+
}
35+
</script>

0 commit comments

Comments
 (0)