mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-28 18:54:09 +00:00
## Summary Resolves issues with #6503 ## Changes - Backport #6400 - Fix circular dependency issue - Backport #6505 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6522-rh-test-Telemetry-Backports-29e6d73d365081258d10c08299bde69b) by [Unito](https://www.unito.io) --------- Co-authored-by: Christian Byrne <cbyrne@comfy.org> Co-authored-by: Christian Byrne <chrbyrne96@gmail.com> Co-authored-by: Claude <noreply@anthropic.com>
194 lines
5.7 KiB
Vue
194 lines
5.7 KiB
Vue
<template>
|
|
<TabPanel value="Credits" class="credits-container h-full">
|
|
<div class="flex h-full flex-col">
|
|
<h2 class="mb-2 text-2xl font-bold">
|
|
{{ $t('credits.credits') }}
|
|
</h2>
|
|
|
|
<Divider />
|
|
|
|
<div class="flex flex-col gap-2">
|
|
<h3 class="text-sm font-medium text-muted">
|
|
{{ $t('credits.yourCreditBalance') }}
|
|
</h3>
|
|
<div class="flex items-center justify-between">
|
|
<UserCredit text-class="text-3xl font-bold" />
|
|
<Skeleton v-if="loading" width="2rem" height="2rem" />
|
|
<Button
|
|
v-else
|
|
:label="$t('credits.purchaseCredits')"
|
|
:loading="loading"
|
|
@click="handlePurchaseCreditsClick"
|
|
/>
|
|
</div>
|
|
<div class="flex flex-row items-center">
|
|
<Skeleton
|
|
v-if="balanceLoading"
|
|
width="12rem"
|
|
height="1rem"
|
|
class="text-xs"
|
|
/>
|
|
<div v-else-if="formattedLastUpdateTime" class="text-xs text-muted">
|
|
{{ $t('credits.lastUpdated') }}: {{ formattedLastUpdateTime }}
|
|
</div>
|
|
<Button
|
|
icon="pi pi-refresh"
|
|
text
|
|
size="small"
|
|
severity="secondary"
|
|
@click="() => authActions.fetchBalance()"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center justify-between">
|
|
<h3>{{ $t('credits.activity') }}</h3>
|
|
<Button
|
|
:label="$t('credits.invoiceHistory')"
|
|
text
|
|
severity="secondary"
|
|
icon="pi pi-arrow-up-right"
|
|
:loading="loading"
|
|
@click="handleCreditsHistoryClick"
|
|
/>
|
|
</div>
|
|
|
|
<template v-if="creditHistory.length > 0">
|
|
<div class="grow">
|
|
<DataTable :value="creditHistory" :show-headers="false">
|
|
<Column field="title" :header="$t('g.name')">
|
|
<template #body="{ data }">
|
|
<div class="text-sm font-medium">{{ data.title }}</div>
|
|
<div class="text-xs text-muted">{{ data.timestamp }}</div>
|
|
</template>
|
|
</Column>
|
|
<Column field="amount" :header="$t('g.amount')">
|
|
<template #body="{ data }">
|
|
<div
|
|
:class="[
|
|
'text-center text-base font-medium',
|
|
data.isPositive ? 'text-sky-500' : 'text-red-400'
|
|
]"
|
|
>
|
|
{{ data.isPositive ? '+' : '-' }}${{
|
|
formatMetronomeCurrency(data.amount, 'usd')
|
|
}}
|
|
</div>
|
|
</template>
|
|
</Column>
|
|
</DataTable>
|
|
</div>
|
|
</template>
|
|
|
|
<Divider />
|
|
|
|
<UsageLogsTable ref="usageLogsTableRef" />
|
|
|
|
<div class="flex flex-row gap-2">
|
|
<Button
|
|
:label="$t('credits.faqs')"
|
|
text
|
|
severity="secondary"
|
|
icon="pi pi-question-circle"
|
|
@click="handleFaqClick"
|
|
/>
|
|
<Button
|
|
:label="$t('subscription.partnerNodesCredits')"
|
|
text
|
|
severity="secondary"
|
|
icon="pi pi-question-circle"
|
|
@click="handleOpenPartnerNodesInfo"
|
|
/>
|
|
<Button
|
|
:label="$t('credits.messageSupport')"
|
|
text
|
|
severity="secondary"
|
|
icon="pi pi-comments"
|
|
@click="handleMessageSupport"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</TabPanel>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import Button from 'primevue/button'
|
|
import Column from 'primevue/column'
|
|
import DataTable from 'primevue/datatable'
|
|
import Divider from 'primevue/divider'
|
|
import Skeleton from 'primevue/skeleton'
|
|
import TabPanel from 'primevue/tabpanel'
|
|
import { computed, ref, watch } from 'vue'
|
|
|
|
import UserCredit from '@/components/common/UserCredit.vue'
|
|
import UsageLogsTable from '@/components/dialog/content/setting/UsageLogsTable.vue'
|
|
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
|
|
import { useTelemetry } from '@/platform/telemetry'
|
|
import { useDialogService } from '@/services/dialogService'
|
|
import { useCommandStore } from '@/stores/commandStore'
|
|
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
|
import { formatMetronomeCurrency } from '@/utils/formatUtil'
|
|
|
|
interface CreditHistoryItemData {
|
|
title: string
|
|
timestamp: string
|
|
amount: number
|
|
isPositive: boolean
|
|
}
|
|
|
|
const dialogService = useDialogService()
|
|
const authStore = useFirebaseAuthStore()
|
|
const authActions = useFirebaseAuthActions()
|
|
const commandStore = useCommandStore()
|
|
const telemetry = useTelemetry()
|
|
const loading = computed(() => authStore.loading)
|
|
const balanceLoading = computed(() => authStore.isFetchingBalance)
|
|
|
|
const usageLogsTableRef = ref<InstanceType<typeof UsageLogsTable> | null>(null)
|
|
|
|
const formattedLastUpdateTime = computed(() =>
|
|
authStore.lastBalanceUpdateTime
|
|
? authStore.lastBalanceUpdateTime.toLocaleString()
|
|
: ''
|
|
)
|
|
|
|
watch(
|
|
() => authStore.lastBalanceUpdateTime,
|
|
(newTime, oldTime) => {
|
|
if (newTime && newTime !== oldTime && usageLogsTableRef.value) {
|
|
usageLogsTableRef.value.refresh()
|
|
}
|
|
}
|
|
)
|
|
|
|
const handlePurchaseCreditsClick = () => {
|
|
dialogService.showTopUpCreditsDialog()
|
|
}
|
|
|
|
const handleCreditsHistoryClick = async () => {
|
|
await authActions.accessBillingPortal()
|
|
}
|
|
|
|
const handleMessageSupport = async () => {
|
|
telemetry?.trackHelpResourceClicked({
|
|
resource_type: 'help_feedback',
|
|
is_external: true,
|
|
source: 'credits_panel'
|
|
})
|
|
await commandStore.execute('Comfy.ContactSupport')
|
|
}
|
|
|
|
const handleFaqClick = () => {
|
|
window.open('https://docs.comfy.org/tutorials/api-nodes/faq', '_blank')
|
|
}
|
|
|
|
const handleOpenPartnerNodesInfo = () => {
|
|
window.open(
|
|
'https://docs.comfy.org/tutorials/api-nodes/overview#api-nodes',
|
|
'_blank'
|
|
)
|
|
}
|
|
|
|
const creditHistory = ref<CreditHistoryItemData[]>([])
|
|
</script>
|