58 lines
2.2 KiB
TypeScript
58 lines
2.2 KiB
TypeScript
import { useEffect, useRef } from 'react'
|
|
import { acct, asList, apiGet } from '../api/client'
|
|
import { ENDPOINTS, ACCOUNTING_ENDPOINTS } from '../api/config'
|
|
import type { ApiCustomer, ApiOwner } from '../api/types'
|
|
import type { Party } from '../types'
|
|
import { useStore } from '../store/AppStore'
|
|
import { createId } from '../utils/id'
|
|
import { findExistingParty, mergeFunZoneParties, partyNeedsSync } from './funzonePartySync'
|
|
|
|
/** Syncs FunZone owners/customers into accounting parties on app load. */
|
|
export function GlobalPartySync() {
|
|
const { ready, upsertPartyAsync } = useStore()
|
|
const synced = useRef(false)
|
|
|
|
useEffect(() => {
|
|
if (!ready || synced.current) return
|
|
synced.current = true
|
|
|
|
const run = async () => {
|
|
try {
|
|
const [owners, customersRaw, initialParties] = await Promise.all([
|
|
apiGet<unknown>(ENDPOINTS.OWNERS).then(asList<ApiOwner>),
|
|
apiGet<unknown>(ENDPOINTS.CUSTOMERS),
|
|
acct.get(ACCOUNTING_ENDPOINTS.PARTIES).then(asList<Party>),
|
|
])
|
|
|
|
const customers: ApiCustomer[] = Array.isArray(customersRaw)
|
|
? (customersRaw as ApiCustomer[])
|
|
: ((customersRaw as { results?: ApiCustomer[] }).results ?? [])
|
|
|
|
let currentParties = initialParties
|
|
const batches = [
|
|
...mergeFunZoneParties(owners, currentParties, 'supplier'),
|
|
...mergeFunZoneParties(customers, currentParties, 'customer'),
|
|
]
|
|
|
|
for (const incoming of batches) {
|
|
const existing = findExistingParty(currentParties, incoming.externalId!, incoming.externalSource)
|
|
if (existing && !partyNeedsSync(existing, incoming)) continue
|
|
const next = { ...incoming, id: existing?.id ?? createId('party-') }
|
|
await upsertPartyAsync(next)
|
|
// Keep the local snapshot in sync so later comparisons in this pass don't re-PATCH.
|
|
currentParties = existing
|
|
? currentParties.map((p) => (p.id === existing.id ? { ...p, ...next } : p))
|
|
: [...currentParties, next]
|
|
}
|
|
// upsertPartyAsync already updates AppStore; avoid a full reload that re-fetches every resource.
|
|
} catch {
|
|
synced.current = false
|
|
}
|
|
}
|
|
|
|
void run()
|
|
}, [ready, upsertPartyAsync])
|
|
|
|
return null
|
|
}
|