gigafibre-fsm/apps/client/src/composables/usePolling.js
louispaulb 4693bcf60c feat: telephony UI, performance indexes, Twilio softphone, lazy-load invoices
- Add PostgreSQL performance indexes migration script (1000x faster queries)
  Sales Invoice: 1,248ms → 28ms, Payment Entry: 443ms → 31ms
  Indexes on customer/party columns for all major tables
- Disable 3CX poller (PBX_ENABLED flag, using Twilio instead)
- Add TelephonyPage: full CRUD UI for Routr/Fonoster resources
  (trunks, agents, credentials, numbers, domains, peers)
- Add PhoneModal + usePhone composable (Twilio WebRTC softphone)
- Lazy-load invoices/payments (initial 5, expand on demand)
- Parallelize all API calls in ClientDetailPage (no waterfall)
- Add targo-hub service (SSE relay, SMS, voice, telephony API)
- Customer portal: invoice detail, ticket detail, messages pages
- Remove dead Ollama nginx upstream

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 13:59:59 -04:00

63 lines
1.6 KiB
JavaScript

import { ref, onUnmounted } from 'vue'
/**
* Smart incremental polling composable.
* Calls `fetchFn()` at `interval` ms. Compares result count/IDs
* with previous to detect new items and trigger `onNew` callback.
*
* @param {Function} fetchFn - async function that returns array of items
* @param {Object} opts
* @param {number} opts.interval - poll interval in ms (default 10000)
* @param {Function} opts.getId - function to get unique ID from item (default: item => item.name)
* @param {Function} opts.onNew - callback when new items detected, receives array of new items
*/
export function usePolling (fetchFn, opts = {}) {
const interval = opts.interval || 10000
const getId = opts.getId || (item => item.name)
const onNew = opts.onNew || (() => {})
const knownIds = ref(new Set())
let timer = null
let running = false
function seedKnownIds (items) {
knownIds.value = new Set(items.map(getId))
}
async function poll () {
if (running) return
running = true
try {
const items = await fetchFn()
const newItems = items.filter(item => !knownIds.value.has(getId(item)))
if (newItems.length) {
for (const item of items) {
knownIds.value.add(getId(item))
}
onNew(newItems, items)
}
} catch {
// Silent fail on poll
} finally {
running = false
}
}
function start () {
stop()
timer = setInterval(poll, interval)
}
function stop () {
if (timer) {
clearInterval(timer)
timer = null
}
}
// Auto-cleanup on component unmount
onUnmounted(stop)
return { start, stop, poll, seedKnownIds }
}