Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
ui improve
  • Loading branch information
jtydhr88 committed Oct 18, 2025
commit 03869d72a7199a0d3449e7c715bb9af8e652d212
3 changes: 2 additions & 1 deletion src/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -1942,7 +1942,8 @@
"waitingForSubscription": "Complete your subscription in the new tab. We'll automatically detect when you're done!",
"subscribe": "Subscribe"
},
"subscribeToRun": "Subscribe to Run"
"subscribeToRun": "Subscribe to Run",
"subscribeNow": "Subscribe Now"
},
"userSettings": {
"title": "User Settings",
Expand Down
99 changes: 99 additions & 0 deletions src/platform/cloud/subscription/components/SubscribeButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<template>
<Button
:label="label || $t('subscription.required.subscribe')"
:size="size"
:class="buttonClass"
:loading="isLoading"
:disabled="isPolling"
severity="primary"
@click="handleSubscribe"
/>
</template>

<script setup lang="ts">
import Button from 'primevue/button'
import { onBeforeUnmount, ref } from 'vue'

import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'

withDefaults(
defineProps<{
label?: string
size?: 'small' | 'large'
buttonClass?: string
}>(),
{
size: 'large',
buttonClass: 'w-full font-bold'
}
)

const emit = defineEmits<{
subscribed: []
}>()

const { subscribe, isActiveSubscription, fetchStatus } = useSubscription()

const isLoading = ref(false)
const isPolling = ref(false)
let pollInterval: number | null = null

const POLL_INTERVAL_MS = 3000 // Poll every 3 seconds
const MAX_POLL_DURATION_MS = 5 * 60 * 1000 // Stop polling after 5 minutes

const startPollingSubscriptionStatus = () => {
isPolling.value = true
isLoading.value = true

const startTime = Date.now()

const poll = async () => {
try {
if (Date.now() - startTime > MAX_POLL_DURATION_MS) {
stopPolling()
return
}

await fetchStatus()

if (isActiveSubscription.value) {
stopPolling()
emit('subscribed')
}
} catch (error) {
console.error(
'[SubscribeButton] Error polling subscription status:',
error
)
}
}

void poll()
pollInterval = window.setInterval(poll, POLL_INTERVAL_MS)
}

const stopPolling = () => {
if (pollInterval) {
clearInterval(pollInterval)
pollInterval = null
}
isPolling.value = false
isLoading.value = false
}

const handleSubscribe = async () => {
isLoading.value = true
try {
await subscribe()

startPollingSubscriptionStatus()
} catch (error) {
console.error('[SubscribeButton] Error initiating subscription:', error)
isLoading.value = false
}
}

onBeforeUnmount(() => {
stopPolling()
})
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
<h2 class="text-2xl">
{{ $t('subscription.title') }}
</h2>
<TopbarBadges />
<TopbarBadges reverse-order />
</div>

<div v-if="isActiveSubscription" class="grow overflow-auto">
<div class="grow overflow-auto">
<div class="rounded-lg border border-charcoal-400 p-4">
<div>
<div class="flex items-center justify-between">
Expand All @@ -19,7 +19,7 @@
}}</span>
<span>{{ $t('subscription.perMonth') }}</span>
</div>
<div class="text-xs text-muted">
<div v-if="isActiveSubscription" class="text-xs text-muted">
{{
$t('subscription.renewsDate', {
date: formattedRenewalDate
Expand All @@ -28,11 +28,19 @@
</div>
</div>
<Button
v-if="isActiveSubscription"
:label="$t('subscription.manageSubscription')"
severity="secondary"
class="text-xs"
@click="manageSubscription"
/>
<SubscribeButton
v-else
:label="$t('subscription.subscribeNow')"
size="small"
button-class="text-xs"
@subscribed="handleSubscribed"
/>
</div>
</div>

Expand Down Expand Up @@ -122,7 +130,7 @@
:label="$t('subscription.viewUsageHistory')"
text
severity="secondary"
class="text-xs text-muted"
class="p-0 text-xs text-muted"
@click="handleViewUsageHistory"
/>
<Button
Expand Down Expand Up @@ -190,6 +198,7 @@ import { computed, onMounted, ref } from 'vue'

import TopbarBadges from '@/components/topbar/TopbarBadges.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import SubscribeButton from '@/platform/cloud/subscription/components/SubscribeButton.vue'
import SubscriptionBenefits from '@/platform/cloud/subscription/components/SubscriptionBenefits.vue'
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
import type { AuditLog } from '@/services/customerEventsService'
Expand Down Expand Up @@ -262,6 +271,15 @@ const handleAddApiCredits = () => {
const handleMessageSupport = async () => {
await commandStore.execute('Comfy.ContactSupport')
}

const handleSubscribed = async () => {
// Refresh all data after successful subscription
await Promise.all([
authActions.fetchBalance(),
fetchStatus(),
fetchLatestEvents()
])
}
</script>

<style scoped>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,99 +42,27 @@
</div>

<div class="flex flex-col">
<Button
:label="$t('subscription.required.subscribe')"
size="large"
class="w-full font-bold"
:loading="isLoading"
:disabled="isPolling"
@click="handleSubscribe"
/>
<SubscribeButton @subscribed="handleSubscribed" />
</div>
</div>
</div>
</template>

<script setup lang="ts">
import Button from 'primevue/button'
import { onBeforeUnmount, ref } from 'vue'

import TopbarBadges from '@/components/topbar/TopbarBadges.vue'
import SubscribeButton from '@/platform/cloud/subscription/components/SubscribeButton.vue'
import SubscriptionBenefits from '@/platform/cloud/subscription/components/SubscriptionBenefits.vue'
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'

const emit = defineEmits<{
close: [subscribed: boolean]
}>()

const { subscribe, isActiveSubscription, formattedMonthlyPrice, fetchStatus } =
useSubscription()

const isLoading = ref(false)
const isPolling = ref(false)
let pollInterval: number | null = null

const POLL_INTERVAL_MS = 3000 // Poll every 3 seconds
const MAX_POLL_DURATION_MS = 5 * 60 * 1000 // Stop polling after 5 minutes

const startPollingSubscriptionStatus = () => {
isPolling.value = true
isLoading.value = true

const startTime = Date.now()

const poll = async () => {
try {
if (Date.now() - startTime > MAX_POLL_DURATION_MS) {
stopPolling()
return
}

await fetchStatus()
const { formattedMonthlyPrice } = useSubscription()

if (isActiveSubscription.value) {
stopPolling()
emit('close', true)
}
} catch (error) {
console.error(
'[SubscriptionRequiredDialog] Error polling subscription status:',
error
)
}
}

void poll()
pollInterval = window.setInterval(poll, POLL_INTERVAL_MS)
}

const stopPolling = () => {
if (pollInterval) {
clearInterval(pollInterval)
pollInterval = null
}
isPolling.value = false
isLoading.value = false
const handleSubscribed = () => {
emit('close', true)
}

const handleSubscribe = async () => {
isLoading.value = true
try {
await subscribe()

startPollingSubscriptionStatus()
} catch (error) {
console.error(
'[SubscriptionRequiredDialog] Error initiating subscription:',
error
)
isLoading.value = false
}
}

onBeforeUnmount(() => {
stopPolling()
})
</script>

<style scoped>
Expand Down
8 changes: 1 addition & 7 deletions src/platform/settings/components/SettingDialogContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ import SearchBox from '@/components/common/SearchBox.vue'
import CurrentUserMessage from '@/components/dialog/content/setting/CurrentUserMessage.vue'
import PanelTemplate from '@/components/dialog/content/setting/PanelTemplate.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
import { isCloud } from '@/platform/distribution/types'
import ColorPaletteMessage from '@/platform/settings/components/ColorPaletteMessage.vue'
import SettingsPanel from '@/platform/settings/components/SettingsPanel.vue'
import { useSettingSearch } from '@/platform/settings/composables/useSettingSearch'
Expand Down Expand Up @@ -108,7 +106,6 @@ const {
} = useSettingSearch()

const authActions = useFirebaseAuthActions()
const { requireActiveSubscription } = useSubscription()

// Sort groups for a category
const sortedGroups = (category: SettingTreeNode): ISettingGroup[] => {
Expand Down Expand Up @@ -136,7 +133,7 @@ const searchResults = computed<ISettingGroup[]>(() =>
)

const tabValue = computed<string>(() =>
inSearch.value ? 'Search Results' : (activeCategory.value?.label ?? '')
inSearch.value ? 'Search Results' : activeCategory.value?.label ?? ''
)

// Don't allow null category to be set outside of search.
Expand All @@ -148,9 +145,6 @@ watch(activeCategory, (_, oldValue) => {
if (activeCategory.value?.key === 'credits') {
void authActions.fetchBalance()
}
if (isCloud && activeCategory.value?.key === 'subscription') {
void requireActiveSubscription()
}
})
</script>

Expand Down
Loading