-
- {{ $t('credits.topUp.addMoreCredits') }}
+
+ {{
+ isInsufficientCredits
+ ? $t('credits.topUp.addMoreCreditsToRun')
+ : $t('credits.topUp.addMoreCredits')
+ }}
-
- {{ $t('credits.topUp.creditsDescription') }}
-
+
+
+ {{ $t('credits.topUp.insufficientWorkflowMessage') }}
+
+
+
+
+ {{ $t('credits.topUp.creditsDescription') }}
+
+
-
- {{
+
+ {{
$t('credits.creditsAvailable')
}}
-
- {{ $t('credits.refreshes', { date: refreshDate }) }}
+
+ {{ $t('credits.refreshes', { date: formattedRenewalDate }) }}
-
+
{{ $t('credits.topUp.howManyCredits') }}
@@ -42,7 +50,7 @@
@select="selectedCredits = option.credits"
/>
-
+
{{ $t('credits.topUp.templateNote') }}
@@ -53,7 +61,8 @@
:loading="loading"
severity="primary"
:label="$t('credits.topUp.buy')"
- class="w-full"
+ :class="['w-full', { 'opacity-30': !selectedCredits || loading }]"
+ :pt="{ label: { class: 'text-white' } }"
@click="handleBuy"
/>
@@ -121,6 +130,7 @@ import {
import UserCredit from '@/components/common/UserCredit.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
+import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
import { useTelemetry } from '@/platform/telemetry'
import CreditTopUpOption from './credit/CreditTopUpOption.vue'
@@ -132,18 +142,17 @@ interface CreditOption {
}
const {
- refreshDate,
isInsufficientCredits = false,
amountOptions = [5, 10, 20, 50],
preselectedAmountOption = 10
} = defineProps<{
- refreshDate?: string
isInsufficientCredits?: boolean
amountOptions?: number[]
preselectedAmountOption?: number
}>()
const { flags } = useFeatureFlags()
+const { formattedRenewalDate } = useSubscription()
// Use feature flag to determine design - defaults to true (new design)
const useNewDesign = computed(() => flags.subscriptionTiersEnabled)
@@ -157,20 +166,20 @@ const loading = ref(false)
const creditOptions: CreditOption[] = [
{
- credits: 1000,
- description: t('credits.topUp.videosEstimate', { count: 100 })
+ credits: 1055, // $5.00
+ description: t('credits.topUp.videosEstimate', { count: 41 })
},
{
- credits: 5000,
- description: t('credits.topUp.videosEstimate', { count: 500 })
+ credits: 2110, // $10.00
+ description: t('credits.topUp.videosEstimate', { count: 82 })
},
{
- credits: 10000,
- description: t('credits.topUp.videosEstimate', { count: 1000 })
+ credits: 4220, // $20.00
+ description: t('credits.topUp.videosEstimate', { count: 184 })
},
{
- credits: 20000,
- description: t('credits.topUp.videosEstimate', { count: 2000 })
+ credits: 10550, // $50.00
+ description: t('credits.topUp.videosEstimate', { count: 412 })
}
]
diff --git a/src/components/dialog/content/credit/CreditTopUpOption.vue b/src/components/dialog/content/credit/CreditTopUpOption.vue
index 4694f15ee..a1bc147ef 100644
--- a/src/components/dialog/content/credit/CreditTopUpOption.vue
+++ b/src/components/dialog/content/credit/CreditTopUpOption.vue
@@ -3,19 +3,17 @@
class="flex items-center justify-between p-2 rounded-lg cursor-pointer transition-all duration-200"
:class="[
selected
- ? 'bg-surface-secondary border-2 border-primary'
- : 'bg-surface-tertiary border border-border-primary hover:bg-surface-secondary'
+ ? 'bg-secondary-background border-2 border-border-default'
+ : 'bg-component-node-disabled hover:bg-secondary-background border-2 border-transparent'
]"
@click="$emit('select')"
>
-
-
- {{ formattedCredits }}
-
-
- {{ description }}
-
-
+
+ {{ formattedCredits }}
+
+
+ {{ description }}
+
@@ -38,6 +36,10 @@ defineEmits<{
const { locale } = useI18n()
const formattedCredits = computed(() => {
- return formatCredits({ value: credits, locale: locale.value })
+ return formatCredits({
+ value: credits,
+ locale: locale.value,
+ numberOptions: { minimumFractionDigits: 0, maximumFractionDigits: 0 }
+ })
})
diff --git a/src/locales/en/main.json b/src/locales/en/main.json
index 36251da0e..225491897 100644
--- a/src/locales/en/main.json
+++ b/src/locales/en/main.json
@@ -1847,6 +1847,8 @@
"seeDetails": "See details",
"topUp": "Top Up",
"addMoreCredits": "Add more credits",
+ "addMoreCreditsToRun": "Add more credits to run",
+ "insufficientWorkflowMessage": "You don't have enough credits to run this workflow.",
"creditsDescription": "Credits are used to run workflows or partner nodes.",
"howManyCredits": "How many credits would you like to add?",
"videosEstimate": "~{count} videos*",
@@ -1869,7 +1871,7 @@
"accountInitialized": "Account initialized",
"unified": {
"message": "Credits have been unified",
- "tooltip": "We've unified payments across Comfy. Everything now runs on Comfy Credits:\n- Partner Nodes (formerly API nodes)\n- Cloud workflows\n\nYour existing Partner node balance has been converted into credits.\nLearn more here."
+ "tooltip": "We've unified payments across Comfy. Everything now runs on Comfy Credits:\n- Partner Nodes (formerly API nodes)\n- Cloud workflows\n\nYour existing Partner node balance has been converted into credits."
}
},
"subscription": {
diff --git a/src/services/dialogService.ts b/src/services/dialogService.ts
index 13e7eebf6..23f1832a8 100644
--- a/src/services/dialogService.ts
+++ b/src/services/dialogService.ts
@@ -386,11 +386,12 @@ export const useDialogService = () => {
return dialogStore.showDialog({
key: 'top-up-credits',
component: TopUpCreditsDialogContent,
- headerComponent: ComfyOrgHeader,
props: options,
dialogComponentProps: {
+ headless: true,
pt: {
- header: { class: 'p-3!' }
+ header: { class: 'p-0! hidden' },
+ content: { class: 'p-0! m-0!' }
}
}
})
diff --git a/tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts b/tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
index 72ad9ecd7..7faf432e7 100644
--- a/tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
+++ b/tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
@@ -32,16 +32,12 @@ describe('CreditTopUpOption', () => {
expect(wrapper.text()).toContain('~500 videos*')
})
- it('applies selected styling when selected', () => {
- const wrapper = mountOption({ selected: true })
- expect(wrapper.find('div').classes()).toContain('bg-surface-secondary')
- expect(wrapper.find('div').classes()).toContain('border-primary')
- })
-
it('applies unselected styling when not selected', () => {
const wrapper = mountOption({ selected: false })
- expect(wrapper.find('div').classes()).toContain('bg-surface-tertiary')
- expect(wrapper.find('div').classes()).toContain('border-border-primary')
+ expect(wrapper.find('div').classes()).toContain(
+ 'bg-component-node-disabled'
+ )
+ expect(wrapper.find('div').classes()).toContain('border-transparent')
})
it('emits select event when clicked', async () => {