[API Node] Fix credits fetch condition (#3575)

This commit is contained in:
Christian Byrne
2025-04-23 09:33:44 +08:00
committed by GitHub
parent a01aa39423
commit e9723407d8
3 changed files with 60 additions and 39 deletions

View File

@@ -86,6 +86,7 @@ import { computed, defineAsyncComponent, watch } from 'vue'
import SearchBox from '@/components/common/SearchBox.vue'
import { useSettingSearch } from '@/composables/setting/useSettingSearch'
import { useSettingUI } from '@/composables/setting/useSettingUI'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { SettingTreeNode } from '@/stores/settingStore'
import { ISettingGroup, SettingParams } from '@/types/settingTypes'
import { flattenTree } from '@/utils/treeUtil'
@@ -135,6 +136,8 @@ const {
getSearchResults
} = useSettingSearch()
const authStore = useFirebaseAuthStore()
// Sort groups for a category
const sortedGroups = (category: SettingTreeNode): ISettingGroup[] => {
return [...(category.children ?? [])]
@@ -165,6 +168,9 @@ watch(activeCategory, (_, oldValue) => {
if (!tabValue.value) {
activeCategory.value = oldValue
}
if (activeCategory.value?.key === 'credits') {
void authStore.fetchBalance()
}
})
</script>

View File

@@ -12,7 +12,14 @@
{{ $t('credits.yourCreditBalance') }}
</h3>
<div class="flex justify-between items-center">
<div class="flex items-center gap-1">
<div v-if="balanceLoading" class="flex items-center gap-1">
<div class="flex items-center gap-2">
<Skeleton shape="circle" width="1.5rem" height="1.5rem" />
</div>
<div class="flex-1"></div>
<Skeleton width="8rem" height="2rem" />
</div>
<div v-else class="flex items-center gap-1">
<Tag
severity="secondary"
icon="pi pi-dollar"
@@ -21,11 +28,7 @@
/>
<div class="text-3xl font-bold">{{ formattedBalance }}</div>
</div>
<ProgressSpinner
v-if="loading"
class="w-12 h-12"
style="--pc-spinner-color: #000"
/>
<Skeleton v-if="loading" width="2rem" height="2rem" />
<Button
v-else
:label="$t('credits.purchaseCredits')"
@@ -34,7 +37,13 @@
/>
</div>
<div class="flex flex-row items-center">
<div v-if="formattedLastUpdateTime" class="text-xs text-muted">
<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
@@ -112,10 +121,10 @@ import Button from 'primevue/button'
import Column from 'primevue/column'
import DataTable from 'primevue/datatable'
import Divider from 'primevue/divider'
import ProgressSpinner from 'primevue/progressspinner'
import Skeleton from 'primevue/skeleton'
import TabPanel from 'primevue/tabpanel'
import Tag from 'primevue/tag'
import { computed, onMounted, ref } from 'vue'
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useDialogService } from '@/services/dialogService'
@@ -133,7 +142,7 @@ const { t } = useI18n()
const dialogService = useDialogService()
const authStore = useFirebaseAuthStore()
const loading = computed(() => authStore.loading)
const balanceLoading = computed(() => authStore.isFetchingBalance)
const formattedBalance = computed(() => {
if (!authStore.balance) return '0.00'
return formatMetronomeCurrency(authStore.balance.amount_micros, 'usd')
@@ -174,10 +183,5 @@ const handleFaqClick = () => {
window.open('https://drip-art.notion.site/api-nodes-faqs', '_blank')
}
// Fetch initial balance when panel is mounted
onMounted(() => {
void authStore.fetchBalance()
})
const creditHistory = ref<CreditHistoryItemData[]>([])
</script>

View File

@@ -45,6 +45,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
const currentUser = ref<User | null>(null)
const isInitialized = ref(false)
const customerCreated = ref(false)
const isFetchingBalance = ref(false)
// Balance state
const balance = ref<GetCustomerBalanceResponse | null>(null)
@@ -95,33 +96,42 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
}
const fetchBalance = async (): Promise<GetCustomerBalanceResponse | null> => {
const token = await getIdToken()
if (!token) {
error.value = 'Cannot fetch balance: User not authenticated'
return null
}
const response = await fetch(`${API_BASE_URL}/customers/balance`, {
headers: {
Authorization: `Bearer ${token}`
}
})
if (!response.ok) {
if (response.status === 404) {
// Customer not found is expected for new users
isFetchingBalance.value = true
try {
const token = await getIdToken()
if (!token) {
error.value = 'Cannot fetch balance: User not authenticated'
isFetchingBalance.value = false
return null
}
const errorData = await response.json()
error.value = `Failed to fetch balance: ${errorData.message}`
return null
}
const balanceData = await response.json()
// Update the last balance update time
lastBalanceUpdateTime.value = new Date()
balance.value = balanceData
return balanceData
const response = await fetch(`${API_BASE_URL}/customers/balance`, {
headers: {
Authorization: `Bearer ${token}`
}
})
if (!response.ok) {
if (response.status === 404) {
// Customer not found is expected for new users
return null
}
const errorData = await response.json()
error.value = `Failed to fetch balance: ${errorData.message}`
return null
}
const balanceData = await response.json()
// Update the last balance update time
lastBalanceUpdateTime.value = new Date()
balance.value = balanceData
return balanceData
} catch (e) {
error.value = `Failed to fetch balance: ${e}`
return null
} finally {
isFetchingBalance.value = false
}
}
const createCustomer = async (
@@ -303,6 +313,7 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
isInitialized,
balance,
lastBalanceUpdateTime,
isFetchingBalance,
// Getters
isAuthenticated,