mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
Checkout on credit add (#3555)
This commit is contained in:
@@ -21,7 +21,11 @@
|
||||
/>
|
||||
<div class="text-3xl font-bold">{{ creditBalance }}</div>
|
||||
</div>
|
||||
<Button :label="$t('credits.purchaseCredits')" />
|
||||
<Button
|
||||
:label="$t('credits.purchaseCredits')"
|
||||
:loading
|
||||
@click="handlePurchaseCreditsClick"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -91,9 +95,17 @@ import TabPanel from 'primevue/tabpanel'
|
||||
import Tag from 'primevue/tag'
|
||||
import { ref } from 'vue'
|
||||
|
||||
// Mock data - in a real implementation, this would come from a store or API
|
||||
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||
import { usdToMicros } from '@/utils/formatUtil'
|
||||
|
||||
// TODO: Mock data - in a real implementation, this would come from a store or API
|
||||
const creditBalance = ref(0.05)
|
||||
|
||||
// TODO: Either: (1) Get checkout URL that allows setting price on Stripe side, (2) Add number selection on credits panel
|
||||
const selectedCurrencyAmount = usdToMicros(10)
|
||||
|
||||
const selectedCurrency = 'usd' // For now, only USD is supported on comfy-api backend
|
||||
|
||||
interface CreditHistoryItemData {
|
||||
title: string
|
||||
timestamp: string
|
||||
@@ -101,6 +113,22 @@ interface CreditHistoryItemData {
|
||||
isPositive: boolean
|
||||
}
|
||||
|
||||
const { initiateCreditPurchase, loading } = useFirebaseAuthStore()
|
||||
|
||||
const handlePurchaseCreditsClick = async () => {
|
||||
const response = await initiateCreditPurchase({
|
||||
amount_micros: selectedCurrencyAmount,
|
||||
currency: selectedCurrency
|
||||
})
|
||||
if (!response) return
|
||||
|
||||
const { checkout_url } = response
|
||||
if (checkout_url !== undefined) {
|
||||
// Go to Stripe checkout page
|
||||
window.open(checkout_url, '_blank')
|
||||
}
|
||||
}
|
||||
|
||||
const creditHistory = ref<CreditHistoryItemData[]>([
|
||||
{
|
||||
title: 'Kling Text-to-Video v1-6',
|
||||
|
||||
@@ -16,6 +16,16 @@ import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useFirebaseAuth } from 'vuefire'
|
||||
|
||||
import { operations } from '@/types/comfyRegistryTypes'
|
||||
|
||||
type CreditPurchaseResponse =
|
||||
operations['InitiateCreditPurchase']['responses']['201']['content']['application/json']
|
||||
type CreditPurchasePayload =
|
||||
operations['InitiateCreditPurchase']['requestBody']['content']['application/json']
|
||||
|
||||
// TODO: Switch to prod api based on environment (requires prod api to be ready)
|
||||
const API_BASE_URL = 'https://stagingapi.comfy.org'
|
||||
|
||||
export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
// State
|
||||
const loading = ref(false)
|
||||
@@ -100,6 +110,39 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
return null
|
||||
}
|
||||
|
||||
const addCredits = async (
|
||||
requestBodyContent: CreditPurchasePayload
|
||||
): Promise<CreditPurchaseResponse | null> => {
|
||||
const token = await getIdToken()
|
||||
if (!token) {
|
||||
error.value = 'Cannot add credits: User not authenticated'
|
||||
return null
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/customers/credit`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`
|
||||
},
|
||||
body: JSON.stringify(requestBodyContent)
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json()
|
||||
error.value = `Failed to initiate credit purchase: ${errorData.message}`
|
||||
return null
|
||||
}
|
||||
|
||||
// TODO: start polling /listBalance until balance is updated or n retries fail or report no change
|
||||
return response.json()
|
||||
}
|
||||
|
||||
const initiateCreditPurchase = async (
|
||||
requestBodyContent: CreditPurchasePayload
|
||||
): Promise<CreditPurchaseResponse | null> =>
|
||||
executeAuthAction((_) => addCredits(requestBodyContent))
|
||||
|
||||
return {
|
||||
// State
|
||||
loading,
|
||||
@@ -118,6 +161,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
logout,
|
||||
getIdToken,
|
||||
loginWithGoogle,
|
||||
loginWithGithub
|
||||
loginWithGithub,
|
||||
initiateCreditPurchase
|
||||
}
|
||||
})
|
||||
|
||||
@@ -415,3 +415,17 @@ export function compareVersions(
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a USD amount to microdollars (1/1,000,000 of a dollar).
|
||||
* This conversion is commonly used in financial systems to avoid floating-point precision issues
|
||||
* by representing monetary values as integers.
|
||||
*
|
||||
* @param usd - The amount in US dollars to convert
|
||||
* @returns The amount in microdollars (multiplied by 1,000,000)
|
||||
* @example
|
||||
* usdToMicros(1.23) // returns 1230000
|
||||
*/
|
||||
export function usdToMicros(usd: number): number {
|
||||
return Math.round(usd * 1_000_000)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user