| |
| |
| |
| |
|
|
| import { defineStore } from 'pinia' |
| import { ref, computed } from 'vue' |
| import subscriptionsAPI from '@/api/subscriptions' |
| import type { UserSubscription } from '@/types' |
|
|
| |
| const CACHE_TTL_MS = 60_000 |
|
|
| |
| let requestGeneration = 0 |
|
|
| export const useSubscriptionStore = defineStore('subscriptions', () => { |
| |
| const activeSubscriptions = ref<UserSubscription[]>([]) |
| const loading = ref(false) |
| const loaded = ref(false) |
| const lastFetchedAt = ref<number | null>(null) |
|
|
| |
| let activePromise: Promise<UserSubscription[]> | null = null |
|
|
| |
| let pollerInterval: ReturnType<typeof setInterval> | null = null |
|
|
| |
| const hasActiveSubscriptions = computed(() => activeSubscriptions.value.length > 0) |
|
|
| |
| |
| |
| |
| async function fetchActiveSubscriptions(force = false): Promise<UserSubscription[]> { |
| const now = Date.now() |
|
|
| |
| if ( |
| !force && |
| loaded.value && |
| lastFetchedAt.value && |
| now - lastFetchedAt.value < CACHE_TTL_MS |
| ) { |
| return activeSubscriptions.value |
| } |
|
|
| |
| if (activePromise && !force) { |
| return activePromise |
| } |
|
|
| const currentGeneration = ++requestGeneration |
|
|
| |
| loading.value = true |
| const requestPromise = subscriptionsAPI |
| .getActiveSubscriptions() |
| .then((data) => { |
| if (currentGeneration === requestGeneration) { |
| activeSubscriptions.value = data |
| loaded.value = true |
| lastFetchedAt.value = Date.now() |
| } |
| return data |
| }) |
| .catch((error) => { |
| console.error('Failed to fetch active subscriptions:', error) |
| throw error |
| }) |
| .finally(() => { |
| if (activePromise === requestPromise) { |
| loading.value = false |
| activePromise = null |
| } |
| }) |
|
|
| activePromise = requestPromise |
|
|
| return activePromise |
| } |
|
|
| |
| |
| |
| function startPolling() { |
| if (pollerInterval) return |
|
|
| pollerInterval = setInterval(() => { |
| fetchActiveSubscriptions(true).catch((error) => { |
| console.error('Subscription polling failed:', error) |
| }) |
| }, 5 * 60 * 1000) |
| } |
|
|
| |
| |
| |
| function stopPolling() { |
| if (pollerInterval) { |
| clearInterval(pollerInterval) |
| pollerInterval = null |
| } |
| } |
|
|
| |
| |
| |
| function clear() { |
| requestGeneration++ |
| activePromise = null |
| activeSubscriptions.value = [] |
| loaded.value = false |
| lastFetchedAt.value = null |
| stopPolling() |
| } |
|
|
| |
| |
| |
| function invalidateCache() { |
| lastFetchedAt.value = null |
| } |
|
|
| return { |
| |
| activeSubscriptions, |
| loading, |
| hasActiveSubscriptions, |
|
|
| |
| fetchActiveSubscriptions, |
| startPolling, |
| stopPolling, |
| clear, |
| invalidateCache |
| } |
| }) |
|
|