mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 03:01:54 +00:00
Re-style TopUpCreditDialog to match design (#3597)
This commit is contained in:
@@ -1,35 +1,67 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col p-6">
|
<div class="flex flex-col w-96 p-2 gap-10">
|
||||||
<div
|
<div v-if="isInsufficientCredits" class="flex flex-col gap-4">
|
||||||
class="flex items-center gap-2"
|
<h1 class="text-2xl font-medium leading-normal my-0">
|
||||||
:class="{ 'text-red-500': isInsufficientCredits }"
|
{{ $t('credits.topUp.insufficientTitle') }}
|
||||||
>
|
</h1>
|
||||||
<i
|
<p class="text-base my-0">
|
||||||
:class="[
|
{{ $t('credits.topUp.insufficientMessage') }}
|
||||||
'text-2xl',
|
</p>
|
||||||
isInsufficientCredits ? 'pi pi-exclamation-triangle' : ''
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
<h2 class="text-2xl font-semibold">
|
|
||||||
{{
|
|
||||||
$t(
|
|
||||||
isInsufficientCredits
|
|
||||||
? 'credits.topUp.insufficientTitle'
|
|
||||||
: 'credits.topUp.title'
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error Message -->
|
|
||||||
<p v-if="isInsufficientCredits" class="text-lg text-muted mt-6">
|
|
||||||
{{ $t('credits.topUp.insufficientMessage') }}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- Balance Section -->
|
<!-- Balance Section -->
|
||||||
<div class="flex justify-between items-center mt-8">
|
<div class="flex justify-between items-center">
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2 w-full">
|
||||||
<div class="text-muted">{{ $t('credits.yourCreditBalance') }}</div>
|
<div class="text-muted text-base">
|
||||||
|
{{ $t('credits.yourCreditBalance') }}
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between w-full">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Tag
|
||||||
|
severity="secondary"
|
||||||
|
icon="pi pi-dollar"
|
||||||
|
rounded
|
||||||
|
class="text-amber-400 p-1"
|
||||||
|
/>
|
||||||
|
<span class="text-2xl">{{ formattedBalance }}</span>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
outlined
|
||||||
|
severity="secondary"
|
||||||
|
:label="$t('credits.topUp.seeDetails')"
|
||||||
|
icon="pi pi-arrow-up-right"
|
||||||
|
@click="handleSeeDetails"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Amount Input Section -->
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<span class="text-muted text-sm"
|
||||||
|
>{{ $t('credits.topUp.quickPurchase') }}:</span
|
||||||
|
>
|
||||||
|
<div class="grid grid-cols-[2fr_1fr] gap-2">
|
||||||
|
<template v-for="amount in amountOptions" :key="amount">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Tag
|
||||||
|
severity="secondary"
|
||||||
|
icon="pi pi-dollar"
|
||||||
|
rounded
|
||||||
|
class="text-amber-400 p-1"
|
||||||
|
/>
|
||||||
|
<span class="text-xl">{{ amount }}</span>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
:severity="
|
||||||
|
preselectedAmountOption === amount ? 'primary' : 'secondary'
|
||||||
|
"
|
||||||
|
:outlined="preselectedAmountOption !== amount"
|
||||||
|
:label="$t('credits.topUp.buyNow')"
|
||||||
|
@click="handleBuyNow(amount)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<Tag
|
<Tag
|
||||||
severity="secondary"
|
severity="secondary"
|
||||||
@@ -37,65 +69,42 @@
|
|||||||
rounded
|
rounded
|
||||||
class="text-amber-400 p-1"
|
class="text-amber-400 p-1"
|
||||||
/>
|
/>
|
||||||
<span class="text-2xl">{{ formattedBalance }}</span>
|
<InputNumber
|
||||||
|
v-model="customAmount"
|
||||||
|
:min="1"
|
||||||
|
:max="1000"
|
||||||
|
:step="1"
|
||||||
|
show-buttons
|
||||||
|
:allow-empty="false"
|
||||||
|
:highlight-on-focus="true"
|
||||||
|
pt:pc-input-text:root="w-24"
|
||||||
|
@blur="
|
||||||
|
(e: InputNumberBlurEvent) => (customAmount = Number(e.value))
|
||||||
|
"
|
||||||
|
@input="
|
||||||
|
(e: InputNumberInputEvent) => (customAmount = Number(e.value))
|
||||||
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<ProgressSpinner v-if="loading" class="w-8 h-8" />
|
||||||
<Button
|
<Button
|
||||||
text
|
v-else
|
||||||
severity="secondary"
|
:label="$t('credits.topUp.buyNow')"
|
||||||
:label="$t('credits.creditsHistory')"
|
|
||||||
icon="pi pi-arrow-up-right"
|
|
||||||
@click="handleSeeDetails"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Amount Input Section -->
|
|
||||||
<div class="flex flex-col gap-2 mt-8">
|
|
||||||
<div>
|
|
||||||
<span class="text-muted">{{ $t('credits.topUp.addCredits') }}</span>
|
|
||||||
<span class="text-muted text-sm ml-1">{{
|
|
||||||
$t('credits.topUp.maxAmount')
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<Tag
|
|
||||||
severity="secondary"
|
severity="secondary"
|
||||||
icon="pi pi-dollar"
|
outlined
|
||||||
rounded
|
@click="handleBuyNow(customAmount)"
|
||||||
class="text-amber-400 p-1"
|
|
||||||
/>
|
|
||||||
<InputNumber
|
|
||||||
v-model="amount"
|
|
||||||
:min="1"
|
|
||||||
:max="1000"
|
|
||||||
:step="1"
|
|
||||||
mode="currency"
|
|
||||||
currency="USD"
|
|
||||||
show-buttons
|
|
||||||
@blur="handleBlur"
|
|
||||||
@input="handleInput"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end mt-8">
|
|
||||||
<ProgressSpinner v-if="loading" class="w-8 h-8" />
|
|
||||||
<Button
|
|
||||||
v-else
|
|
||||||
severity="primary"
|
|
||||||
:label="$t('credits.topUp.buyNow')"
|
|
||||||
:disabled="!amount || amount > 1000"
|
|
||||||
:pt="{
|
|
||||||
root: { class: 'px-8' }
|
|
||||||
}"
|
|
||||||
@click="handleBuyNow"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Button from 'primevue/button'
|
import Button from 'primevue/button'
|
||||||
import InputNumber from 'primevue/inputnumber'
|
import InputNumber, {
|
||||||
|
type InputNumberBlurEvent,
|
||||||
|
type InputNumberInputEvent
|
||||||
|
} from 'primevue/inputnumber'
|
||||||
import ProgressSpinner from 'primevue/progressspinner'
|
import ProgressSpinner from 'primevue/progressspinner'
|
||||||
import Tag from 'primevue/tag'
|
import Tag from 'primevue/tag'
|
||||||
import { computed, onBeforeUnmount, ref } from 'vue'
|
import { computed, onBeforeUnmount, ref } from 'vue'
|
||||||
@@ -103,25 +112,21 @@ import { computed, onBeforeUnmount, ref } from 'vue'
|
|||||||
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||||
import { formatMetronomeCurrency, usdToMicros } from '@/utils/formatUtil'
|
import { formatMetronomeCurrency, usdToMicros } from '@/utils/formatUtil'
|
||||||
|
|
||||||
defineProps<{
|
const {
|
||||||
|
isInsufficientCredits = false,
|
||||||
|
amountOptions = [5, 10, 20, 50],
|
||||||
|
preselectedAmountOption = 10
|
||||||
|
} = defineProps<{
|
||||||
isInsufficientCredits?: boolean
|
isInsufficientCredits?: boolean
|
||||||
|
amountOptions?: number[]
|
||||||
|
preselectedAmountOption?: number
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const authStore = useFirebaseAuthStore()
|
const authStore = useFirebaseAuthStore()
|
||||||
const amount = ref<number>(9.99)
|
const customAmount = ref<number>(100)
|
||||||
const didClickBuyNow = ref(false)
|
const didClickBuyNow = ref(false)
|
||||||
const loading = computed(() => authStore.loading)
|
const loading = computed(() => authStore.loading)
|
||||||
|
|
||||||
const handleBlur = (e: any) => {
|
|
||||||
if (e.target.value) {
|
|
||||||
amount.value = parseFloat(e.target.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleInput = (e: any) => {
|
|
||||||
amount.value = e.value
|
|
||||||
}
|
|
||||||
|
|
||||||
const formattedBalance = computed(() => {
|
const formattedBalance = computed(() => {
|
||||||
if (!authStore.balance) return '0.000'
|
if (!authStore.balance) return '0.000'
|
||||||
return formatMetronomeCurrency(authStore.balance.amount_micros, 'usd')
|
return formatMetronomeCurrency(authStore.balance.amount_micros, 'usd')
|
||||||
@@ -133,11 +138,9 @@ const handleSeeDetails = async () => {
|
|||||||
window.open(response.billing_portal_url, '_blank')
|
window.open(response.billing_portal_url, '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleBuyNow = async () => {
|
const handleBuyNow = async (amount: number) => {
|
||||||
if (!amount.value) return
|
|
||||||
|
|
||||||
const response = await authStore.initiateCreditPurchase({
|
const response = await authStore.initiateCreditPurchase({
|
||||||
amount_micros: usdToMicros(amount.value),
|
amount_micros: usdToMicros(amount),
|
||||||
currency: 'usd'
|
currency: 'usd'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1148,12 +1148,12 @@
|
|||||||
"messageSupport": "Message Support",
|
"messageSupport": "Message Support",
|
||||||
"lastUpdated": "Last updated",
|
"lastUpdated": "Last updated",
|
||||||
"topUp": {
|
"topUp": {
|
||||||
"title": "Add to Credit Balance",
|
|
||||||
"insufficientTitle": "Insufficient Credits",
|
"insufficientTitle": "Insufficient Credits",
|
||||||
"insufficientMessage": "You don't have enough credits to run this workflow.",
|
"insufficientMessage": "You don't have enough credits to run this workflow.",
|
||||||
"addCredits": "Add credits to your balance",
|
"quickPurchase": "Quick Purchase",
|
||||||
"maxAmount": "(Max. $1,000 USD)",
|
"maxAmount": "(Max. $1,000 USD)",
|
||||||
"buyNow": "Buy now"
|
"buyNow": "Buy now",
|
||||||
|
"seeDetails": "See details"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"userSettings": {
|
"userSettings": {
|
||||||
|
|||||||
@@ -110,12 +110,12 @@
|
|||||||
"messageSupport": "Contactar soporte",
|
"messageSupport": "Contactar soporte",
|
||||||
"purchaseCredits": "Comprar créditos",
|
"purchaseCredits": "Comprar créditos",
|
||||||
"topUp": {
|
"topUp": {
|
||||||
"addCredits": "Agregar créditos a tu saldo",
|
|
||||||
"buyNow": "Comprar ahora",
|
"buyNow": "Comprar ahora",
|
||||||
"insufficientMessage": "No tienes suficientes créditos para ejecutar este flujo de trabajo.",
|
"insufficientMessage": "No tienes suficientes créditos para ejecutar este flujo de trabajo.",
|
||||||
"insufficientTitle": "Créditos insuficientes",
|
"insufficientTitle": "Créditos insuficientes",
|
||||||
"maxAmount": "(Máx. $1,000 USD)",
|
"maxAmount": "(Máx. $1,000 USD)",
|
||||||
"title": "Agregar al saldo de créditos"
|
"quickPurchase": "Compra rápida",
|
||||||
|
"seeDetails": "Ver detalles"
|
||||||
},
|
},
|
||||||
"yourCreditBalance": "Tu saldo de créditos"
|
"yourCreditBalance": "Tu saldo de créditos"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -110,12 +110,12 @@
|
|||||||
"messageSupport": "Contacter le support",
|
"messageSupport": "Contacter le support",
|
||||||
"purchaseCredits": "Acheter des crédits",
|
"purchaseCredits": "Acheter des crédits",
|
||||||
"topUp": {
|
"topUp": {
|
||||||
"addCredits": "Ajouter des crédits à votre solde",
|
|
||||||
"buyNow": "Acheter maintenant",
|
"buyNow": "Acheter maintenant",
|
||||||
"insufficientMessage": "Vous n'avez pas assez de crédits pour exécuter ce workflow.",
|
"insufficientMessage": "Vous n'avez pas assez de crédits pour exécuter ce workflow.",
|
||||||
"insufficientTitle": "Crédits insuffisants",
|
"insufficientTitle": "Crédits insuffisants",
|
||||||
"maxAmount": "(Max. 1 000 $ US)",
|
"maxAmount": "(Max. 1 000 $ US)",
|
||||||
"title": "Ajouter au solde de crédits"
|
"quickPurchase": "Achat rapide",
|
||||||
|
"seeDetails": "Voir les détails"
|
||||||
},
|
},
|
||||||
"yourCreditBalance": "Votre solde de crédits"
|
"yourCreditBalance": "Votre solde de crédits"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -110,12 +110,12 @@
|
|||||||
"messageSupport": "サポートにメッセージ",
|
"messageSupport": "サポートにメッセージ",
|
||||||
"purchaseCredits": "クレジットを購入",
|
"purchaseCredits": "クレジットを購入",
|
||||||
"topUp": {
|
"topUp": {
|
||||||
"addCredits": "残高にクレジットを追加",
|
|
||||||
"buyNow": "今すぐ購入",
|
"buyNow": "今すぐ購入",
|
||||||
"insufficientMessage": "このワークフローを実行するのに十分なクレジットがありません。",
|
"insufficientMessage": "このワークフローを実行するのに十分なクレジットがありません。",
|
||||||
"insufficientTitle": "クレジット不足",
|
"insufficientTitle": "クレジット不足",
|
||||||
"maxAmount": "(最大 $1,000 USD)",
|
"maxAmount": "(最大 $1,000 USD)",
|
||||||
"title": "クレジット残高を追加"
|
"quickPurchase": "クイック購入",
|
||||||
|
"seeDetails": "詳細を見る"
|
||||||
},
|
},
|
||||||
"yourCreditBalance": "あなたのクレジット残高"
|
"yourCreditBalance": "あなたのクレジット残高"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -110,12 +110,12 @@
|
|||||||
"messageSupport": "지원 문의",
|
"messageSupport": "지원 문의",
|
||||||
"purchaseCredits": "크레딧 구매",
|
"purchaseCredits": "크레딧 구매",
|
||||||
"topUp": {
|
"topUp": {
|
||||||
"addCredits": "잔액에 크레딧 추가",
|
|
||||||
"buyNow": "지금 구매",
|
"buyNow": "지금 구매",
|
||||||
"insufficientMessage": "이 워크플로우를 실행하기에 크레딧이 부족합니다.",
|
"insufficientMessage": "이 워크플로우를 실행하기에 크레딧이 부족합니다.",
|
||||||
"insufficientTitle": "크레딧 부족",
|
"insufficientTitle": "크레딧 부족",
|
||||||
"maxAmount": "(최대 $1,000 USD)",
|
"maxAmount": "(최대 $1,000 USD)",
|
||||||
"title": "크레딧 잔액 충전"
|
"quickPurchase": "빠른 구매",
|
||||||
|
"seeDetails": "자세히 보기"
|
||||||
},
|
},
|
||||||
"yourCreditBalance": "보유 크레딧 잔액"
|
"yourCreditBalance": "보유 크레딧 잔액"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -110,12 +110,12 @@
|
|||||||
"messageSupport": "Связаться с поддержкой",
|
"messageSupport": "Связаться с поддержкой",
|
||||||
"purchaseCredits": "Купить кредиты",
|
"purchaseCredits": "Купить кредиты",
|
||||||
"topUp": {
|
"topUp": {
|
||||||
"addCredits": "Добавить кредиты на баланс",
|
|
||||||
"buyNow": "Купить сейчас",
|
"buyNow": "Купить сейчас",
|
||||||
"insufficientMessage": "У вас недостаточно кредитов для запуска этого рабочего процесса.",
|
"insufficientMessage": "У вас недостаточно кредитов для запуска этого рабочего процесса.",
|
||||||
"insufficientTitle": "Недостаточно кредитов",
|
"insufficientTitle": "Недостаточно кредитов",
|
||||||
"maxAmount": "(Макс. $1,000 USD)",
|
"maxAmount": "(Макс. $1,000 USD)",
|
||||||
"title": "Пополнить баланс кредитов"
|
"quickPurchase": "Быстрая покупка",
|
||||||
|
"seeDetails": "Смотреть детали"
|
||||||
},
|
},
|
||||||
"yourCreditBalance": "Ваш баланс кредитов"
|
"yourCreditBalance": "Ваш баланс кредитов"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -110,12 +110,12 @@
|
|||||||
"messageSupport": "联系客服",
|
"messageSupport": "联系客服",
|
||||||
"purchaseCredits": "购买积分",
|
"purchaseCredits": "购买积分",
|
||||||
"topUp": {
|
"topUp": {
|
||||||
"addCredits": "为您的余额充值",
|
|
||||||
"buyNow": "立即购买",
|
"buyNow": "立即购买",
|
||||||
"insufficientMessage": "您的积分不足,无法运行此工作流。",
|
"insufficientMessage": "您的积分不足,无法运行此工作流。",
|
||||||
"insufficientTitle": "积分不足",
|
"insufficientTitle": "积分不足",
|
||||||
"maxAmount": "(最高 $1,000 美元)",
|
"maxAmount": "(最高 $1,000 美元)",
|
||||||
"title": "充值余额"
|
"quickPurchase": "快速购买",
|
||||||
|
"seeDetails": "查看详情"
|
||||||
},
|
},
|
||||||
"yourCreditBalance": "您的积分余额"
|
"yourCreditBalance": "您的积分余额"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user