(
namespace: string = `list/${anonListCount++}`,
delay: number = THRESHOLD.AnimationShort,
finder: (obj1: T, obj2: T) => boolean = (obj1, obj2) => obj1 === obj2
)
| 29 | let anonListCount = 1; |
| 30 | |
| 31 | export function createAsyncListService<T>( |
| 32 | namespace: string = `list/${anonListCount++}`, |
| 33 | delay: number = THRESHOLD.AnimationShort, |
| 34 | finder: (obj1: T, obj2: T) => boolean = (obj1, obj2) => obj1 === obj2 |
| 35 | ) { |
| 36 | const initialState: AsyncState<T> = { |
| 37 | items: [], |
| 38 | entering: [], |
| 39 | leaving: [], |
| 40 | }; |
| 41 | |
| 42 | const delayFn = (req: ListRequest<T>) => { |
| 43 | const duration = req.method === 'reset' ? 0 : delay; |
| 44 | return after(duration, req); |
| 45 | }; |
| 46 | |
| 47 | return createQueueingService< |
| 48 | ListRequest<T>, |
| 49 | ListRequest<T>, |
| 50 | Error, |
| 51 | AsyncState<T> |
| 52 | >(namespace, delayFn, (ACs) => |
| 53 | immutablyReduce((state = initialState, event) => { |
| 54 | // Request updates entering only |
| 55 | if (ACs.started.match(event)) { |
| 56 | const { item, method } = event.payload; |
| 57 | |
| 58 | if (method === 'push') { |
| 59 | state.items.push(item); |
| 60 | state.entering.push(item); |
| 61 | } |
| 62 | if (method === 'pop') { |
| 63 | const last = state.items[state.items.length - 1]; |
| 64 | state.leaving.push(last); |
| 65 | } |
| 66 | if (method === 'remove') { |
| 67 | const leaver = state.items.find((obj) => finder(obj, item))!; |
| 68 | state.leaving.push(leaver); |
| 69 | } |
| 70 | if (method === 'reset') { |
| 71 | state.items = event.payload.items; |
| 72 | state.entering = []; |
| 73 | state.leaving = []; |
| 74 | } |
| 75 | } |
| 76 | // Next removes from entering or leaving, and becomes member of items |
| 77 | if (ACs.next.match(event)) { |
| 78 | const { item, method } = event.payload; |
| 79 | if (method === 'push') { |
| 80 | state.entering = state.entering.filter((obj) => !finder(obj, item)); |
| 81 | } |
| 82 | if (method === 'pop') { |
| 83 | const lessThan = (_, idx) => idx < state.items.length - 1; |
| 84 | const rest = state.items.filter(lessThan); |
| 85 | state.items = rest; |
| 86 | state.leaving = state.leaving.filter(lessThan); |
| 87 | } |
| 88 | if (method === 'remove') { |
no test coverage detected