Skip to content

Commit b23ab6b

Browse files
feat: add comfy credit domain helpers
1 parent c21ded6 commit b23ab6b

File tree

8 files changed

+293
-268
lines changed

8 files changed

+293
-268
lines changed

src/base/credits/comfyCredits.ts

Lines changed: 80 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
1-
/**
2-
* Fixed conversion rate between USD and Comfy credits.
3-
* 1 credit costs 210 cents ($2.10).
4-
*/
5-
export const COMFY_CREDIT_RATE_CENTS = 210
6-
7-
export const COMFY_CREDIT_RATE_USD = COMFY_CREDIT_RATE_CENTS / 100
8-
91
const DEFAULT_NUMBER_FORMAT: Intl.NumberFormatOptions = {
102
minimumFractionDigits: 2,
113
maximumFractionDigits: 2
124
}
135

14-
const formatNumber = (
15-
value: number,
16-
options: Intl.NumberFormatOptions = DEFAULT_NUMBER_FORMAT,
6+
const formatNumber = ({
7+
value,
8+
locale,
9+
options
10+
}: {
11+
value: number
1712
locale?: string
18-
) => {
13+
options?: Intl.NumberFormatOptions
14+
}): string => {
1915
const merged: Intl.NumberFormatOptions = {
2016
...DEFAULT_NUMBER_FORMAT,
2117
...options
@@ -32,166 +28,88 @@ const formatNumber = (
3228
return new Intl.NumberFormat(locale, merged).format(value)
3329
}
3430

35-
export const centsToUsd = (cents: number): number => cents / 100
31+
export const COMFY_CREDIT_RATE_CENTS = 210
32+
export const COMFY_CREDIT_RATE_USD = COMFY_CREDIT_RATE_CENTS / 100
33+
3634
export const usdToCents = (usd: number): number => Math.round(usd * 100)
3735

38-
/**
39-
* Converts a USD amount into Comfy credits.
40-
*/
41-
export function usdToComfyCredits(usd: number): number {
42-
return usd / COMFY_CREDIT_RATE_USD
43-
}
36+
export const centsToCredits = (cents: number): number =>
37+
cents / COMFY_CREDIT_RATE_CENTS
4438

45-
/**
46-
* Converts USD cents into Comfy credits.
47-
*/
48-
export function centsToComfyCredits(cents: number): number {
49-
return cents / COMFY_CREDIT_RATE_CENTS
50-
}
39+
export const creditsToCents = (credits: number): number =>
40+
Math.round(credits * COMFY_CREDIT_RATE_CENTS)
5141

52-
/**
53-
* Converts Comfy credits back to USD.
54-
*/
55-
export function comfyCreditsToUsd(credits: number): number {
56-
return credits * COMFY_CREDIT_RATE_USD
57-
}
42+
export const usdToCredits = (usd: number): number =>
43+
centsToCredits(usdToCents(usd))
5844

59-
/**
60-
* Converts Comfy credits to cents.
61-
*/
62-
export function comfyCreditsToCents(credits: number): number {
63-
return credits * COMFY_CREDIT_RATE_CENTS
64-
}
45+
export const creditsToUsd = (credits: number): number =>
46+
creditsToCents(credits) / 100
6547

66-
export function formatUsdFromCents(
67-
cents: number,
68-
options?: Intl.NumberFormatOptions,
48+
export type FormatOptions = {
49+
value: number
6950
locale?: string
70-
): string {
71-
return formatNumber(
72-
centsToUsd(cents),
73-
{ ...DEFAULT_NUMBER_FORMAT, ...options },
74-
locale
75-
)
51+
numberOptions?: Intl.NumberFormatOptions
7652
}
7753

78-
/**
79-
* Formats credits to a localized numeric string (no unit suffix).
80-
*/
81-
export function formatComfyCreditsAmount(
82-
credits: number,
83-
options?: Intl.NumberFormatOptions,
54+
export const formatCredits = ({
55+
value,
56+
locale,
57+
numberOptions
58+
}: FormatOptions): string =>
59+
formatNumber({ value, locale, options: numberOptions })
60+
61+
export const formatCreditsFromCents = ({
62+
cents,
63+
locale,
64+
numberOptions
65+
}: {
66+
cents: number
8467
locale?: string
85-
): string {
86-
return formatNumber(credits, { ...DEFAULT_NUMBER_FORMAT, ...options }, locale)
87-
}
88-
89-
type FormatCreditsOptions = {
90-
unit?: string | null
9168
numberOptions?: Intl.NumberFormatOptions
69+
}): string =>
70+
formatCredits({
71+
value: centsToCredits(cents),
72+
locale,
73+
numberOptions
74+
})
75+
76+
export const formatCreditsFromUsd = ({
77+
usd,
78+
locale,
79+
numberOptions
80+
}: {
81+
usd: number
9282
locale?: string
93-
}
94-
95-
export function formatComfyCreditsLabel(
96-
credits: number,
97-
{ unit = 'credits', numberOptions, locale }: FormatCreditsOptions = {}
98-
): string {
99-
const formatted = formatComfyCreditsAmount(credits, numberOptions, locale)
100-
return unit ? `${formatted} ${unit}` : formatted
101-
}
102-
103-
export function formatComfyCreditsLabelFromCents(
104-
cents: number,
105-
options?: FormatCreditsOptions
106-
): string {
107-
return formatComfyCreditsLabel(centsToComfyCredits(cents), options)
108-
}
109-
110-
export function formatComfyCreditsLabelFromUsd(
111-
usd: number,
112-
options?: FormatCreditsOptions
113-
): string {
114-
return formatComfyCreditsLabel(usdToComfyCredits(usd), options)
115-
}
116-
117-
export function formatComfyCreditsRangeLabelFromUsd(
118-
minUsd: number,
119-
maxUsd: number,
120-
{
121-
unit = 'credits',
122-
numberOptions,
83+
numberOptions?: Intl.NumberFormatOptions
84+
}): string =>
85+
formatCredits({
86+
value: usdToCredits(usd),
12387
locale,
124-
separator = '–'
125-
}: FormatCreditsOptions & {
126-
separator?: string
127-
} = {}
128-
): string {
129-
const min = formatComfyCreditsAmount(
130-
usdToComfyCredits(minUsd),
131-
numberOptions,
132-
locale
133-
)
134-
const max = formatComfyCreditsAmount(
135-
usdToComfyCredits(maxUsd),
136-
numberOptions,
137-
locale
138-
)
139-
const joined = `${min}${separator}${max}`
140-
return unit ? `${joined} ${unit}` : joined
141-
}
142-
143-
const USD_RANGE_REGEX = /(~?)\$(\d+(?:\.\d+)?)\s*[-]\s*\$?(\d+(?:\.\d+)?)/g
144-
const USD_VALUE_REGEX = /(~?)\$(\d+(?:\.\d+)?)/g
145-
146-
/**
147-
* Converts a USD-denoted string (e.g., "$0.45-1.2/Run") into a credits string.
148-
* Any "$X" occurrences become "Y credits". Ranges are rendered as "Y–Z credits".
149-
*/
150-
export function convertUsdLabelToCredits(
151-
label: string,
152-
options?: FormatCreditsOptions
153-
): string {
154-
if (!label) return label
155-
const unit = options?.unit ?? 'credits'
156-
const numberOptions = options?.numberOptions
157-
const locale = options?.locale
158-
159-
const formatSingle = (usd: number) =>
160-
formatComfyCreditsLabel(usdToComfyCredits(usd), {
161-
unit,
162-
numberOptions,
163-
locale
164-
})
165-
166-
const formatRange = (min: number, max: number, prefix = '') => {
167-
const minStr = formatComfyCreditsAmount(
168-
usdToComfyCredits(min),
169-
numberOptions,
170-
locale
171-
)
172-
const maxStr = formatComfyCreditsAmount(
173-
usdToComfyCredits(max),
174-
numberOptions,
175-
locale
176-
)
177-
const joined = `${minStr}${maxStr}`
178-
return unit ? `${prefix}${joined} ${unit}` : `${prefix}${joined}`
179-
}
180-
181-
let converted = label
182-
converted = converted.replace(
183-
USD_RANGE_REGEX,
184-
(_match, prefix = '', minUsd, maxUsd) =>
185-
formatRange(parseFloat(minUsd), parseFloat(maxUsd), prefix)
186-
)
187-
188-
converted = converted.replace(
189-
USD_VALUE_REGEX,
190-
(_match, prefix = '', amount) => {
191-
const formatted = formatSingle(parseFloat(amount))
192-
return `${prefix}${formatted}`
193-
}
194-
)
195-
196-
return converted
197-
}
88+
numberOptions
89+
})
90+
91+
export const formatUsd = ({
92+
value,
93+
locale,
94+
numberOptions
95+
}: FormatOptions): string =>
96+
formatNumber({
97+
value,
98+
locale,
99+
options: numberOptions
100+
})
101+
102+
export const formatUsdFromCents = ({
103+
cents,
104+
locale,
105+
numberOptions
106+
}: {
107+
cents: number
108+
locale?: string
109+
numberOptions?: Intl.NumberFormatOptions
110+
}): string =>
111+
formatUsd({
112+
value: cents / 100,
113+
locale,
114+
numberOptions
115+
})

src/components/common/UserCredit.vue

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<div v-else class="flex items-center gap-1">
1010
<Tag
1111
severity="secondary"
12-
icon="pi pi-dollar"
12+
icon="pi pi-wallet"
1313
rounded
1414
class="p-1 text-amber-400"
1515
/>
@@ -21,19 +21,26 @@
2121
import Skeleton from 'primevue/skeleton'
2222
import Tag from 'primevue/tag'
2323
import { computed } from 'vue'
24+
import { useI18n } from 'vue-i18n'
2425
26+
import { formatCreditsFromCents } from '@/base/credits/comfyCredits'
2527
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
26-
import { formatMetronomeCurrency } from '@/utils/formatUtil'
2728
2829
const { textClass } = defineProps<{
2930
textClass?: string
3031
}>()
3132
3233
const authStore = useFirebaseAuthStore()
3334
const balanceLoading = computed(() => authStore.isFetchingBalance)
35+
const { t, locale } = useI18n()
3436
3537
const formattedBalance = computed(() => {
36-
if (!authStore.balance) return '0.00'
37-
return formatMetronomeCurrency(authStore.balance.amount_micros, 'usd')
38+
// Backend returns cents despite the *_micros naming convention.
39+
const cents = authStore.balance?.amount_micros ?? 0
40+
const amount = formatCreditsFromCents({
41+
cents,
42+
locale: locale.value
43+
})
44+
return `${amount} ${t('credits.credits')}`
3845
})
3946
</script>

0 commit comments

Comments
 (0)