parent
a33d5ef48f
commit
52fb43ae4a
@ -1,4 +1,4 @@ |
|||||||
import { reducer, initialState } from '../../js/pages/block' |
import { reducer, initialState } from '../../js/pages/blocks' |
||||||
|
|
||||||
test('CHANNEL_DISCONNECTED', () => { |
test('CHANNEL_DISCONNECTED', () => { |
||||||
const state = initialState |
const state = initialState |
@ -0,0 +1,232 @@ |
|||||||
|
import { reducer, initialState } from '../../js/pages/pending_transactions' |
||||||
|
|
||||||
|
test('CHANNEL_DISCONNECTED', () => { |
||||||
|
const state = initialState |
||||||
|
const action = { |
||||||
|
type: 'CHANNEL_DISCONNECTED' |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.channelDisconnected).toBe(true) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => { |
||||||
|
test('single transaction', () => { |
||||||
|
const state = initialState |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHash: '0x00', |
||||||
|
transactionHtml: 'test' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newPendingTransactions).toEqual(['test']) |
||||||
|
expect(output.newPendingTransactionHashesBatch.length).toEqual(0) |
||||||
|
expect(output.pendingTransactionCount).toEqual(1) |
||||||
|
}) |
||||||
|
test('large batch of transactions', () => { |
||||||
|
const state = initialState |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHash: '0x01', |
||||||
|
transactionHtml: 'test 1' |
||||||
|
},{ |
||||||
|
transactionHash: '0x02', |
||||||
|
transactionHtml: 'test 2' |
||||||
|
},{ |
||||||
|
transactionHash: '0x03', |
||||||
|
transactionHtml: 'test 3' |
||||||
|
},{ |
||||||
|
transactionHash: '0x04', |
||||||
|
transactionHtml: 'test 4' |
||||||
|
},{ |
||||||
|
transactionHash: '0x05', |
||||||
|
transactionHtml: 'test 5' |
||||||
|
},{ |
||||||
|
transactionHash: '0x06', |
||||||
|
transactionHtml: 'test 6' |
||||||
|
},{ |
||||||
|
transactionHash: '0x07', |
||||||
|
transactionHtml: 'test 7' |
||||||
|
},{ |
||||||
|
transactionHash: '0x08', |
||||||
|
transactionHtml: 'test 8' |
||||||
|
},{ |
||||||
|
transactionHash: '0x09', |
||||||
|
transactionHtml: 'test 9' |
||||||
|
},{ |
||||||
|
transactionHash: '0x10', |
||||||
|
transactionHtml: 'test 10' |
||||||
|
},{ |
||||||
|
transactionHash: '0x11', |
||||||
|
transactionHtml: 'test 11' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newPendingTransactions).toEqual([]) |
||||||
|
expect(output.newPendingTransactionHashesBatch.length).toEqual(11) |
||||||
|
expect(output.pendingTransactionCount).toEqual(11) |
||||||
|
}) |
||||||
|
test('single transaction after single transaction', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
newPendingTransactions: ['test 1'], |
||||||
|
pendingTransactionCount: 1 |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHash: '0x02', |
||||||
|
transactionHtml: 'test 2' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newPendingTransactions).toEqual(['test 1', 'test 2']) |
||||||
|
expect(output.newPendingTransactionHashesBatch.length).toEqual(0) |
||||||
|
expect(output.pendingTransactionCount).toEqual(2) |
||||||
|
}) |
||||||
|
test('single transaction after large batch of transactions', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
newPendingTransactionHashesBatch: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11'] |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHash: '0x12', |
||||||
|
transactionHtml: 'test 12' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newPendingTransactions).toEqual([]) |
||||||
|
expect(output.newPendingTransactionHashesBatch.length).toEqual(12) |
||||||
|
}) |
||||||
|
test('large batch of transactions after large batch of transactions', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
newPendingTransactionHashesBatch: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11'] |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHash: '0x12', |
||||||
|
transactionHtml: 'test 12' |
||||||
|
},{ |
||||||
|
transactionHash: '0x13', |
||||||
|
transactionHtml: 'test 13' |
||||||
|
},{ |
||||||
|
transactionHash: '0x14', |
||||||
|
transactionHtml: 'test 14' |
||||||
|
},{ |
||||||
|
transactionHash: '0x15', |
||||||
|
transactionHtml: 'test 15' |
||||||
|
},{ |
||||||
|
transactionHash: '0x16', |
||||||
|
transactionHtml: 'test 16' |
||||||
|
},{ |
||||||
|
transactionHash: '0x17', |
||||||
|
transactionHtml: 'test 17' |
||||||
|
},{ |
||||||
|
transactionHash: '0x18', |
||||||
|
transactionHtml: 'test 18' |
||||||
|
},{ |
||||||
|
transactionHash: '0x19', |
||||||
|
transactionHtml: 'test 19' |
||||||
|
},{ |
||||||
|
transactionHash: '0x20', |
||||||
|
transactionHtml: 'test 20' |
||||||
|
},{ |
||||||
|
transactionHash: '0x21', |
||||||
|
transactionHtml: 'test 21' |
||||||
|
},{ |
||||||
|
transactionHash: '0x22', |
||||||
|
transactionHtml: 'test 22' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newPendingTransactions).toEqual([]) |
||||||
|
expect(output.newPendingTransactionHashesBatch.length).toEqual(22) |
||||||
|
}) |
||||||
|
test('after disconnection', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
channelDisconnected: true |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHash: '0x00', |
||||||
|
transactionHtml: 'test' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newPendingTransactions).toEqual([]) |
||||||
|
}) |
||||||
|
test('on page 2+', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
beyondPageOne: true, |
||||||
|
pendingTransactionCount: 1 |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHash: '0x00', |
||||||
|
transactionHtml: 'test' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newPendingTransactions).toEqual([]) |
||||||
|
expect(output.pendingTransactionCount).toEqual(2) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('RECEIVED_NEW_TRANSACTION', () => { |
||||||
|
test('single transaction collated', () => { |
||||||
|
const state = { ...initialState, pendingTransactionCount: 2 } |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_TRANSACTION', |
||||||
|
msg: { |
||||||
|
transactionHash: '0x00' |
||||||
|
} |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.pendingTransactionCount).toBe(1) |
||||||
|
expect(output.newTransactionHashes).toEqual(['0x00']) |
||||||
|
}) |
||||||
|
test('single transaction collated after batch', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
newPendingTransactionHashesBatch: ['0x01', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11'] |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_TRANSACTION', |
||||||
|
msg: { |
||||||
|
transactionHash: '0x01' |
||||||
|
} |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newPendingTransactionHashesBatch.length).toEqual(10) |
||||||
|
expect(output.newPendingTransactionHashesBatch).not.toContain('0x01') |
||||||
|
}) |
||||||
|
test('on page 2+', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
beyondPageOne: true, |
||||||
|
pendingTransactionCount: 2 |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_TRANSACTION', |
||||||
|
msg: { |
||||||
|
transactionHash: '0x01' |
||||||
|
} |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.pendingTransactionCount).toEqual(1) |
||||||
|
}) |
||||||
|
}) |
@ -0,0 +1,160 @@ |
|||||||
|
import { reducer, initialState } from '../../js/pages/transactions' |
||||||
|
|
||||||
|
test('CHANNEL_DISCONNECTED', () => { |
||||||
|
const state = initialState |
||||||
|
const action = { |
||||||
|
type: 'CHANNEL_DISCONNECTED' |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.channelDisconnected).toBe(true) |
||||||
|
expect(output.batchCountAccumulator).toBe(0) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('RECEIVED_NEW_TRANSACTION_BATCH', () => { |
||||||
|
test('single transaction', () => { |
||||||
|
const state = initialState |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHtml: 'test' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newTransactions).toEqual(['test']) |
||||||
|
expect(output.batchCountAccumulator).toEqual(0) |
||||||
|
expect(output.transactionCount).toEqual(1) |
||||||
|
}) |
||||||
|
test('large batch of transactions', () => { |
||||||
|
const state = initialState |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHtml: 'test 1' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 2' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 3' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 4' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 5' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 6' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 7' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 8' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 9' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 10' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 11' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newTransactions).toEqual([]) |
||||||
|
expect(output.batchCountAccumulator).toEqual(11) |
||||||
|
expect(output.transactionCount).toEqual(11) |
||||||
|
}) |
||||||
|
test('single transaction after single transaction', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
newTransactions: ['test 1'] |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHtml: 'test 2' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newTransactions).toEqual(['test 1', 'test 2']) |
||||||
|
expect(output.batchCountAccumulator).toEqual(0) |
||||||
|
}) |
||||||
|
test('single transaction after large batch of transactions', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
batchCountAccumulator: 11 |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHtml: 'test 12' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newTransactions).toEqual([]) |
||||||
|
expect(output.batchCountAccumulator).toEqual(12) |
||||||
|
}) |
||||||
|
test('large batch of transactions after large batch of transactions', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
batchCountAccumulator: 11 |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHtml: 'test 12' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 13' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 14' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 15' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 16' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 17' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 18' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 19' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 20' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 21' |
||||||
|
},{ |
||||||
|
transactionHtml: 'test 22' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newTransactions).toEqual([]) |
||||||
|
expect(output.batchCountAccumulator).toEqual(22) |
||||||
|
}) |
||||||
|
test('after disconnection', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
channelDisconnected: true |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHtml: 'test' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newTransactions).toEqual([]) |
||||||
|
expect(output.batchCountAccumulator).toEqual(0) |
||||||
|
}) |
||||||
|
test('on page 2+', () => { |
||||||
|
const state = Object.assign({}, initialState, { |
||||||
|
beyondPageOne: true, |
||||||
|
transactionCount: 1 |
||||||
|
}) |
||||||
|
const action = { |
||||||
|
type: 'RECEIVED_NEW_TRANSACTION_BATCH', |
||||||
|
msgs: [{ |
||||||
|
transactionHtml: 'test' |
||||||
|
}] |
||||||
|
} |
||||||
|
const output = reducer(state, action) |
||||||
|
|
||||||
|
expect(output.newTransactions).toEqual([]) |
||||||
|
expect(output.batchCountAccumulator).toEqual(0) |
||||||
|
expect(output.transactionCount).toEqual(2) |
||||||
|
}) |
||||||
|
}) |
@ -0,0 +1,131 @@ |
|||||||
|
import $ from 'jquery' |
||||||
|
import _ from 'lodash' |
||||||
|
import URI from 'urijs' |
||||||
|
import humps from 'humps' |
||||||
|
import numeral from 'numeral' |
||||||
|
import socket from '../socket' |
||||||
|
import { updateAllAges } from '../lib/from_now' |
||||||
|
import { batchChannel, initRedux, slideDownPrepend, slideUpRemove } from '../utils' |
||||||
|
|
||||||
|
const BATCH_THRESHOLD = 10 |
||||||
|
|
||||||
|
export const initialState = { |
||||||
|
newPendingTransactionHashesBatch: [], |
||||||
|
beyondPageOne: null, |
||||||
|
channelDisconnected: false, |
||||||
|
newPendingTransactions: [], |
||||||
|
newTransactionHashes: [], |
||||||
|
pendingTransactionCount: null |
||||||
|
} |
||||||
|
|
||||||
|
export function reducer (state = initialState, action) { |
||||||
|
switch (action.type) { |
||||||
|
case 'PAGE_LOAD': { |
||||||
|
return Object.assign({}, state, { |
||||||
|
beyondPageOne: action.beyondPageOne, |
||||||
|
pendingTransactionCount: numeral(action.pendingTransactionCount).value() |
||||||
|
}) |
||||||
|
} |
||||||
|
case 'CHANNEL_DISCONNECTED': { |
||||||
|
return Object.assign({}, state, { |
||||||
|
channelDisconnected: true |
||||||
|
}) |
||||||
|
} |
||||||
|
case 'RECEIVED_NEW_TRANSACTION': { |
||||||
|
if (state.channelDisconnected) return state |
||||||
|
|
||||||
|
return Object.assign({}, state, { |
||||||
|
newPendingTransactionHashesBatch: _.without(state.newPendingTransactionHashesBatch, action.msg.transactionHash), |
||||||
|
pendingTransactionCount: state.pendingTransactionCount - 1, |
||||||
|
newTransactionHashes: [action.msg.transactionHash] |
||||||
|
}) |
||||||
|
} |
||||||
|
case 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH': { |
||||||
|
if (state.channelDisconnected) return state |
||||||
|
|
||||||
|
const pendingTransactionCount = state.pendingTransactionCount + action.msgs.length |
||||||
|
|
||||||
|
if (state.beyondPageOne) return Object.assign({}, state, { pendingTransactionCount }) |
||||||
|
|
||||||
|
if (!state.newPendingTransactionHashesBatch.length && action.msgs.length < BATCH_THRESHOLD) { |
||||||
|
return Object.assign({}, state, { |
||||||
|
newPendingTransactions: [ |
||||||
|
...state.newPendingTransactions, |
||||||
|
..._.map(action.msgs, 'transactionHtml') |
||||||
|
], |
||||||
|
pendingTransactionCount |
||||||
|
}) |
||||||
|
} else { |
||||||
|
return Object.assign({}, state, { |
||||||
|
newPendingTransactionHashesBatch: [ |
||||||
|
...state.newPendingTransactionHashesBatch, |
||||||
|
..._.map(action.msgs, 'transactionHash') |
||||||
|
], |
||||||
|
pendingTransactionCount |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
default: |
||||||
|
return state |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const $transactionPendingListPage = $('[data-page="transaction-pending-list"]') |
||||||
|
if ($transactionPendingListPage.length) { |
||||||
|
initRedux(reducer, { |
||||||
|
main (store) { |
||||||
|
store.dispatch({ |
||||||
|
type: 'PAGE_LOAD', |
||||||
|
pendingTransactionCount: $('[data-selector="transaction-pending-count"]').text(), |
||||||
|
beyondPageOne: !!humps.camelizeKeys(URI(window.location).query(true)).insertedAt |
||||||
|
}) |
||||||
|
const transactionsChannel = socket.channel(`transactions:new_transaction`) |
||||||
|
transactionsChannel.join() |
||||||
|
transactionsChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' })) |
||||||
|
transactionsChannel.on('transaction', (msg) => |
||||||
|
store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION', msg: humps.camelizeKeys(msg) }) |
||||||
|
) |
||||||
|
const pendingTransactionsChannel = socket.channel(`transactions:new_pending_transaction`) |
||||||
|
pendingTransactionsChannel.join() |
||||||
|
pendingTransactionsChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' })) |
||||||
|
pendingTransactionsChannel.on('pending_transaction', batchChannel((msgs) => |
||||||
|
store.dispatch({ type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) })) |
||||||
|
) |
||||||
|
}, |
||||||
|
render (state, oldState) { |
||||||
|
const $channelBatching = $('[data-selector="channel-batching-message"]') |
||||||
|
const $channelBatchingCount = $('[data-selector="channel-batching-count"]') |
||||||
|
const $channelDisconnected = $('[data-selector="channel-disconnected-message"]') |
||||||
|
const $pendingTransactionsList = $('[data-selector="transactions-pending-list"]') |
||||||
|
const $pendingTransactionsCount = $('[data-selector="transaction-pending-count"]') |
||||||
|
|
||||||
|
if (state.channelDisconnected) $channelDisconnected.show() |
||||||
|
if (oldState.pendingTransactionCount !== state.pendingTransactionCount) { |
||||||
|
$pendingTransactionsCount.empty().append(numeral(state.pendingTransactionCount).format()) |
||||||
|
} |
||||||
|
if (oldState.newTransactionHashes !== state.newTransactionHashes && state.newTransactionHashes.length > 0) { |
||||||
|
const $transaction = $(`[data-transaction-hash="${state.newTransactionHashes[0]}"]`) |
||||||
|
$transaction.addClass('shrink-out') |
||||||
|
setTimeout(() => { |
||||||
|
if ($transaction.length === 1 && $transaction.siblings().length === 0 && state.pendingTransactionCount > 0) { |
||||||
|
window.location.href = URI(window.location).removeQuery('inserted_at').removeQuery('hash').toString() |
||||||
|
} else { |
||||||
|
slideUpRemove($transaction) |
||||||
|
} |
||||||
|
}, 400) |
||||||
|
} |
||||||
|
if (state.newPendingTransactionHashesBatch.length) { |
||||||
|
$channelBatching.show() |
||||||
|
$channelBatchingCount[0].innerHTML = numeral(state.newPendingTransactionHashesBatch.length).format() |
||||||
|
} else { |
||||||
|
$channelBatching.hide() |
||||||
|
} |
||||||
|
if (oldState.newPendingTransactions !== state.newPendingTransactions) { |
||||||
|
const newTransactionsToInsert = state.newPendingTransactions.slice(oldState.newPendingTransactions.length) |
||||||
|
slideDownPrepend($pendingTransactionsList, newTransactionsToInsert.reverse().join('')) |
||||||
|
|
||||||
|
updateAllAges() |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
@ -0,0 +1,100 @@ |
|||||||
|
import $ from 'jquery' |
||||||
|
import _ from 'lodash' |
||||||
|
import URI from 'urijs' |
||||||
|
import humps from 'humps' |
||||||
|
import numeral from 'numeral' |
||||||
|
import socket from '../socket' |
||||||
|
import { updateAllAges } from '../lib/from_now' |
||||||
|
import { batchChannel, initRedux, slideDownPrepend } from '../utils' |
||||||
|
|
||||||
|
const BATCH_THRESHOLD = 10 |
||||||
|
|
||||||
|
export const initialState = { |
||||||
|
batchCountAccumulator: 0, |
||||||
|
beyondPageOne: null, |
||||||
|
channelDisconnected: false, |
||||||
|
newTransactions: [], |
||||||
|
transactionCount: null |
||||||
|
} |
||||||
|
|
||||||
|
export function reducer (state = initialState, action) { |
||||||
|
switch (action.type) { |
||||||
|
case 'PAGE_LOAD': { |
||||||
|
return Object.assign({}, state, { |
||||||
|
beyondPageOne: action.beyondPageOne, |
||||||
|
transactionCount: numeral(action.transactionCount).value() |
||||||
|
}) |
||||||
|
} |
||||||
|
case 'CHANNEL_DISCONNECTED': { |
||||||
|
return Object.assign({}, state, { |
||||||
|
channelDisconnected: true, |
||||||
|
batchCountAccumulator: 0 |
||||||
|
}) |
||||||
|
} |
||||||
|
case 'RECEIVED_NEW_TRANSACTION_BATCH': { |
||||||
|
if (state.channelDisconnected) return state |
||||||
|
|
||||||
|
const transactionCount = state.transactionCount + action.msgs.length |
||||||
|
|
||||||
|
if (state.beyondPageOne) return Object.assign({}, state, { transactionCount }) |
||||||
|
|
||||||
|
if (!state.batchCountAccumulator && action.msgs.length < BATCH_THRESHOLD) { |
||||||
|
return Object.assign({}, state, { |
||||||
|
newTransactions: [ |
||||||
|
...state.newTransactions, |
||||||
|
..._.map(action.msgs, 'transactionHtml') |
||||||
|
], |
||||||
|
transactionCount |
||||||
|
}) |
||||||
|
} else { |
||||||
|
return Object.assign({}, state, { |
||||||
|
batchCountAccumulator: state.batchCountAccumulator + action.msgs.length, |
||||||
|
transactionCount |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
default: |
||||||
|
return state |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const $transactionListPage = $('[data-page="transaction-list"]') |
||||||
|
if ($transactionListPage.length) { |
||||||
|
initRedux(reducer, { |
||||||
|
main (store) { |
||||||
|
store.dispatch({ |
||||||
|
type: 'PAGE_LOAD', |
||||||
|
transactionCount: $('[data-selector="transaction-count"]').text(), |
||||||
|
beyondPageOne: !!humps.camelizeKeys(URI(window.location).query(true)).index |
||||||
|
}) |
||||||
|
const transactionsChannel = socket.channel(`transactions:new_transaction`) |
||||||
|
transactionsChannel.join() |
||||||
|
transactionsChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' })) |
||||||
|
transactionsChannel.on('transaction', batchChannel((msgs) => |
||||||
|
store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) })) |
||||||
|
) |
||||||
|
}, |
||||||
|
render (state, oldState) { |
||||||
|
const $channelBatching = $('[data-selector="channel-batching-message"]') |
||||||
|
const $channelBatchingCount = $('[data-selector="channel-batching-count"]') |
||||||
|
const $channelDisconnected = $('[data-selector="channel-disconnected-message"]') |
||||||
|
const $transactionsList = $('[data-selector="transactions-list"]') |
||||||
|
const $transactionCount = $('[data-selector="transaction-count"]') |
||||||
|
|
||||||
|
if (state.channelDisconnected) $channelDisconnected.show() |
||||||
|
if (oldState.transactionCount !== state.transactionCount) $transactionCount.empty().append(numeral(state.transactionCount).format()) |
||||||
|
if (state.batchCountAccumulator) { |
||||||
|
$channelBatching.show() |
||||||
|
$channelBatchingCount[0].innerHTML = numeral(state.batchCountAccumulator).format() |
||||||
|
} else { |
||||||
|
$channelBatching.hide() |
||||||
|
} |
||||||
|
if (oldState.newTransactions !== state.newTransactions) { |
||||||
|
const newTransactionsToInsert = state.newTransactions.slice(oldState.newTransactions.length) |
||||||
|
slideDownPrepend($transactionsList, newTransactionsToInsert.reverse().join('')) |
||||||
|
|
||||||
|
updateAllAges() |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
Loading…
Reference in new issue