Files
archy/neode-ui/src/composables/peerPaymentOperations.ts
T

39 lines
1.9 KiB
TypeScript

import { computed, reactive } from 'vue'
export type PaymentSelection = { peer: string; item: string; generation: number } | null
export type PaymentOperation = { peer: string; item: string; generation: number; kind: string; token: symbol }
/** In-flight UI ownership complements durable node/browser attempt journals.
* An old callback may persist its own receipt, but cannot own a new modal. */
export function usePeerPaymentOperations(selection: () => PaymentSelection) {
const slots = reactive(new Map<string, PaymentOperation>())
const key = (peer: string, item: string) => JSON.stringify([peer, item])
function begin(kind: string, peer: string, item: string): PaymentOperation | null {
const index = key(peer, item)
if (slots.has(index)) return null
const current = selection()
if (!current || current.peer !== peer || current.item !== item) return null
const operation = { peer, item, generation: current.generation, kind, token: Symbol(kind) }
slots.set(index, operation)
return operation
}
function selected(operation: PaymentOperation): boolean {
const current = selection()
return slots.get(key(operation.peer, operation.item))?.token === operation.token
&& current?.peer === operation.peer && current?.item === operation.item && current?.generation === operation.generation
}
function finish(operation: PaymentOperation): boolean {
const index = key(operation.peer, operation.item)
// Never reset a newer operation's busy flag, even for the same file.
const owned = slots.get(index)?.token === operation.token
const wasSelected = owned && selected(operation)
if (owned) slots.delete(index)
return wasSelected
}
const current = computed(() => {
const value = selection()
return value ? slots.get(key(value.peer, value.item)) : undefined
})
return { begin, selected, finish, current, busy: computed(() => current.value !== undefined) }
}