Skip to content

Commit 47d2e14

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

File tree

2 files changed

+54
-188
lines changed

2 files changed

+54
-188
lines changed

src/base/credits/comfyCredits.ts

Lines changed: 30 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
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
@@ -32,166 +24,50 @@ const formatNumber = (
3224
return new Intl.NumberFormat(locale, merged).format(value)
3325
}
3426

35-
export const centsToUsd = (cents: number): number => cents / 100
27+
export const COMFY_CREDIT_RATE_CENTS = 210
28+
export const COMFY_CREDIT_RATE_USD = COMFY_CREDIT_RATE_CENTS / 100
29+
3630
export const usdToCents = (usd: number): number => Math.round(usd * 100)
31+
export const centsToUsd = (cents: number): number => cents / 100
3732

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-
}
33+
export const centsToCredits = (cents: number): number =>
34+
cents / COMFY_CREDIT_RATE_CENTS
4435

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

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

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

66-
export function formatUsdFromCents(
67-
cents: number,
45+
export const formatCredits = (
46+
credits: number,
6847
options?: Intl.NumberFormatOptions,
6948
locale?: string
70-
): string {
71-
return formatNumber(
72-
centsToUsd(cents),
73-
{ ...DEFAULT_NUMBER_FORMAT, ...options },
74-
locale
75-
)
76-
}
49+
): string => formatNumber(credits, options, locale)
7750

78-
/**
79-
* Formats credits to a localized numeric string (no unit suffix).
80-
*/
81-
export function formatComfyCreditsAmount(
82-
credits: number,
51+
export const formatCreditsFromCents = (
52+
cents: number,
8353
options?: Intl.NumberFormatOptions,
8454
locale?: string
85-
): string {
86-
return formatNumber(credits, { ...DEFAULT_NUMBER_FORMAT, ...options }, locale)
87-
}
55+
): string => formatCredits(centsToCredits(cents), options, locale)
8856

89-
type FormatCreditsOptions = {
90-
unit?: string | null
91-
numberOptions?: Intl.NumberFormatOptions
57+
export const formatCreditsFromUsd = (
58+
usd: number,
59+
options?: Intl.NumberFormatOptions,
9260
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-
}
61+
): string => formatCredits(usdToCredits(usd), options, locale)
10262

103-
export function formatComfyCreditsLabelFromCents(
63+
export const formatUsdFromCents = (
10464
cents: number,
105-
options?: FormatCreditsOptions
106-
): string {
107-
return formatComfyCreditsLabel(centsToComfyCredits(cents), options)
108-
}
65+
options?: Intl.NumberFormatOptions,
66+
locale?: string
67+
): string => formatNumber(centsToUsd(cents), options, locale)
10968

110-
export function formatComfyCreditsLabelFromUsd(
69+
export const formatUsd = (
11170
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,
123-
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-
}
71+
options?: Intl.NumberFormatOptions,
72+
locale?: string
73+
): string => formatNumber(usd, options, locale)

tests-ui/tests/base/credits/comfyCredits.test.ts

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ import { describe, expect, it } from 'vitest'
33
import {
44
COMFY_CREDIT_RATE_CENTS,
55
COMFY_CREDIT_RATE_USD,
6-
centsToComfyCredits,
7-
comfyCreditsToCents,
8-
comfyCreditsToUsd,
9-
convertUsdLabelToCredits,
10-
formatComfyCreditsAmount,
11-
formatComfyCreditsLabel,
12-
formatComfyCreditsRangeLabelFromUsd,
13-
usdToComfyCredits
6+
centsToCredits,
7+
creditsToCents,
8+
creditsToUsd,
9+
formatCredits,
10+
formatCreditsFromCents,
11+
formatCreditsFromUsd,
12+
formatUsd,
13+
formatUsdFromCents,
14+
usdToCents,
15+
usdToCredits
1416
} from '@/base/credits/comfyCredits'
1517

1618
describe('comfyCredits helpers', () => {
@@ -19,37 +21,25 @@ describe('comfyCredits helpers', () => {
1921
expect(COMFY_CREDIT_RATE_USD).toBeCloseTo(2.1)
2022
})
2123

22-
it('converts USD and cents to credits', () => {
23-
expect(usdToComfyCredits(2.1)).toBeCloseTo(1)
24-
expect(usdToComfyCredits(10.5)).toBeCloseTo(5)
25-
expect(centsToComfyCredits(210)).toBeCloseTo(1)
26-
expect(centsToComfyCredits(1050)).toBeCloseTo(5)
24+
it('converts between USD and cents', () => {
25+
expect(usdToCents(1.23)).toBe(123)
26+
expect(formatUsdFromCents(123)).toBe('1.23')
2727
})
2828

29-
it('converts credits back to USD and cents', () => {
30-
expect(comfyCreditsToUsd(1)).toBeCloseTo(2.1)
31-
expect(comfyCreditsToUsd(3.5)).toBeCloseTo(7.35)
32-
expect(comfyCreditsToCents(1)).toBe(210)
33-
expect(comfyCreditsToCents(3.5)).toBeCloseTo(735)
29+
it('converts cents to credits and back', () => {
30+
expect(centsToCredits(210)).toBeCloseTo(1)
31+
expect(creditsToCents(5)).toBe(1050)
3432
})
3533

36-
it('formats credits with localized precision', () => {
37-
expect(formatComfyCreditsAmount(1234.5678)).toBe('1,234.57')
38-
expect(
39-
formatComfyCreditsLabel(1.2345, {
40-
unit: 'credits',
41-
numberOptions: { maximumFractionDigits: 1 }
42-
})
43-
).toBe('1.2 credits')
34+
it('converts USD to credits and back', () => {
35+
expect(usdToCredits(2.1)).toBeCloseTo(1)
36+
expect(creditsToUsd(3.5)).toBeCloseTo(7.35)
4437
})
4538

46-
it('formats ranges and USD strings into credits', () => {
47-
expect(formatComfyCreditsRangeLabelFromUsd(2.1, 4.2)).toBe(
48-
'1.00–2.00 credits'
49-
)
50-
expect(convertUsdLabelToCredits('$2.10/Run')).toBe('1.00 credits/Run')
51-
expect(convertUsdLabelToCredits('~$2.10-$4.20/Run')).toBe(
52-
'~1.00–2.00 credits/Run'
53-
)
39+
it('formats credits and USD values', () => {
40+
expect(formatCredits(1234.567)).toBe('1,234.57')
41+
expect(formatCreditsFromCents(210)).toBe('1.00')
42+
expect(formatCreditsFromUsd(4.2)).toBe('2.00')
43+
expect(formatUsd(4.2)).toBe('4.20')
5444
})
5545
})

0 commit comments

Comments
 (0)