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
24 changes: 21 additions & 3 deletions src/components/common/UserCredit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
<Skeleton width="8rem" height="2rem" />
</div>
<div v-else class="flex items-center gap-1">
<Tag severity="secondary" rounded class="p-1 text-amber-400">
<Tag
v-if="!showCreditsOnly"
severity="secondary"
rounded
class="p-1 text-amber-400"
>
<template #icon>
<i
:class="
Expand All @@ -18,7 +23,9 @@
/>
</template>
</Tag>
<div :class="textClass">{{ formattedBalance }}</div>
<div :class="textClass">
{{ showCreditsOnly ? formattedCreditsOnly : formattedBalance }}
</div>
</div>
</template>

Expand All @@ -32,8 +39,9 @@ import { formatCreditsFromCents } from '@/base/credits/comfyCredits'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'

const { textClass } = defineProps<{
const { textClass, showCreditsOnly } = defineProps<{
textClass?: string
showCreditsOnly?: boolean
}>()

const authStore = useFirebaseAuthStore()
Expand All @@ -50,4 +58,14 @@ const formattedBalance = computed(() => {
})
return `${amount} ${t('credits.credits')}`
})

const formattedCreditsOnly = computed(() => {
// Backend returns cents despite the *_micros naming convention.
const cents = authStore.balance?.amount_micros ?? 0
const amount = formatCreditsFromCents({
cents,
locale: locale.value
})
return amount
})
</script>
61 changes: 35 additions & 26 deletions src/components/dialog/content/TopUpCreditsDialogContent.vue
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
<template>
<!-- New Credits Design (default) -->
<div
v-if="useNewDesign"
class="flex w-96 flex-col gap-8 p-8 bg-node-component-surface rounded-2xl border border-border-primary"
>
<div v-if="useNewDesign" class="flex w-112 flex-col gap-8 p-8">
<!-- Header -->
<div class="flex flex-col gap-4">
<h1 class="text-2xl font-semibold text-foreground-primary m-0">
{{ $t('credits.topUp.addMoreCredits') }}
<h1 class="text-2xl font-semibold text-white m-0">
{{
isInsufficientCredits
? $t('credits.topUp.addMoreCreditsToRun')
: $t('credits.topUp.addMoreCredits')
}}
</h1>
<p class="text-sm text-foreground-secondary m-0">
{{ $t('credits.topUp.creditsDescription') }}
</p>
<div v-if="isInsufficientCredits" class="flex flex-col gap-2">
<p class="text-sm text-muted-foreground m-0 w-96">
{{ $t('credits.topUp.insufficientWorkflowMessage') }}
</p>
</div>
<div v-else class="flex flex-col gap-2">
<p class="text-sm text-muted-foreground m-0">
{{ $t('credits.topUp.creditsDescription') }}
</p>
</div>
</div>

<!-- Current Balance Section -->
<div class="flex flex-col gap-4">
<div class="flex items-baseline gap-2">
<UserCredit text-class="text-3xl font-bold" />
<span class="text-sm text-foreground-secondary">{{
<UserCredit text-class="text-3xl font-bold" show-credits-only />
<span class="text-sm text-muted-foreground">{{
$t('credits.creditsAvailable')
}}</span>
</div>
<div v-if="refreshDate" class="text-sm text-foreground-secondary">
{{ $t('credits.refreshes', { date: refreshDate }) }}
<div v-if="formattedRenewalDate" class="text-sm text-muted-foreground">
{{ $t('credits.refreshes', { date: formattedRenewalDate }) }}
</div>
</div>

<!-- Credit Options Section -->
<div class="flex flex-col gap-4">
<span class="text-sm text-foreground-secondary">
<span class="text-sm text-muted-foreground">
{{ $t('credits.topUp.howManyCredits') }}
</span>
<div class="flex flex-col gap-2">
Expand All @@ -42,7 +50,7 @@
@select="selectedCredits = option.credits"
/>
</div>
<div class="text-xs text-foreground-secondary">
<div class="text-xs text-muted-foreground w-96">
{{ $t('credits.topUp.templateNote') }}
</div>
</div>
Expand All @@ -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"
/>
</div>
Expand Down Expand Up @@ -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'
Expand All @@ -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)

Expand All @@ -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 })
}
]

Expand Down
18 changes: 8 additions & 10 deletions src/components/dialog/content/credit/CreditTopUpOption.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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-white'
: 'bg-component-node-disabled hover:bg-secondary-background border-2 border-transparent'
]"
@click="$emit('select')"
>
<div class="flex flex-col">
<span class="text-base font-medium text-foreground-primary">
{{ formattedCredits }}
</span>
<span class="text-sm text-foreground-secondary">
{{ description }}
</span>
</div>
<span class="text-base font-bold text-white">
{{ formattedCredits }}
</span>
<span class="text-sm font-normal text-white">
{{ description }}
</span>
</div>
</template>

Expand Down
2 changes: 2 additions & 0 deletions src/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -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*",
Expand Down
5 changes: 3 additions & 2 deletions src/services/dialogService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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!' }
}
}
})
Expand Down
Loading