diff --git a/app/components/Activity/ActivityModal.js b/app/components/Activity/ActivityModal.js index 414ffe89..703fb108 100644 --- a/app/components/Activity/ActivityModal.js +++ b/app/components/Activity/ActivityModal.js @@ -10,8 +10,8 @@ import InvoiceModal from './InvoiceModal' import styles from './ActivityModal.scss' const ActivityModal = ({ - modalType, - modalProps, + itemType, + item, ticker, currentTicker, network, @@ -25,11 +25,12 @@ const ActivityModal = ({ INVOICE: InvoiceModal } - if (!modalType) { + if (!item) { return null } - const SpecificModal = MODAL_COMPONENTS[modalType] + const SpecificModal = MODAL_COMPONENTS[itemType] + return (
@@ -38,7 +39,7 @@ const ActivityModal = ({
{invoice.creation_date * 1000}

{!invoice.settled &&

Not Paid

} + {invoice.settled &&

Paid

}
@@ -107,7 +108,7 @@ const InvoiceModal = ({ } InvoiceModal.propTypes = { - invoice: PropTypes.object.isRequired, + item: PropTypes.object.isRequired, ticker: PropTypes.object.isRequired, currentTicker: PropTypes.object.isRequired, toggleCurrencyProps: PropTypes.object.isRequired diff --git a/app/components/Activity/InvoiceModal.scss b/app/components/Activity/InvoiceModal.scss index 398a9e1b..566a24fa 100644 --- a/app/components/Activity/InvoiceModal.scss +++ b/app/components/Activity/InvoiceModal.scss @@ -96,7 +96,12 @@ text-align: right; .notPaid { - color: #ff8a65; + color: $orange; + margin-top: 5px; + } + + .paid { + color: $green; margin-top: 5px; } } diff --git a/app/components/Activity/PaymentModal.js b/app/components/Activity/PaymentModal.js index a3288a91..3242cd63 100644 --- a/app/components/Activity/PaymentModal.js +++ b/app/components/Activity/PaymentModal.js @@ -14,7 +14,7 @@ import Value from 'components/Value' import styles from './PaymentModal.scss' const PaymentModal = ({ - payment, + item: payment, ticker, currentTicker, @@ -88,7 +88,7 @@ const PaymentModal = ({ ) PaymentModal.propTypes = { - payment: PropTypes.object.isRequired, + item: PropTypes.object.isRequired, ticker: PropTypes.object.isRequired, currentTicker: PropTypes.object.isRequired, diff --git a/app/components/Activity/TransactionModal.js b/app/components/Activity/TransactionModal.js index a2449e26..266b48bc 100644 --- a/app/components/Activity/TransactionModal.js +++ b/app/components/Activity/TransactionModal.js @@ -16,7 +16,7 @@ import Value from 'components/Value' import styles from './TransactionModal.scss' const TransactionModal = ({ - transaction, + item: transaction, ticker, currentTicker, network, @@ -107,7 +107,7 @@ const TransactionModal = ({ ) TransactionModal.propTypes = { - transaction: PropTypes.object.isRequired, + item: PropTypes.object.isRequired, ticker: PropTypes.object.isRequired, currentTicker: PropTypes.object.isRequired, diff --git a/app/reducers/activity.js b/app/reducers/activity.js index 761efb09..dcc343f5 100644 --- a/app/reducers/activity.js +++ b/app/reducers/activity.js @@ -13,8 +13,8 @@ const initialState = { { key: 'PENDING_ACTIVITY', name: 'Pending' } ], modal: { - modalType: null, - modalProps: {}, + itemType: null, + itemId: null, showCurrencyFilters: false }, searchActive: false, @@ -42,11 +42,11 @@ export const UPDATE_SEARCH_TEXT = 'UPDATE_SEARCH_TEXT' // ------------------------------------ // Actions // ------------------------------------ -export function showActivityModal(modalType, modalProps) { +export function showActivityModal(itemType, itemId) { return { type: SHOW_ACTIVITY_MODAL, - modalType, - modalProps + itemType, + itemId } } @@ -100,11 +100,11 @@ export function toggleExpiredRequests() { // Action Handlers // ------------------------------------ const ACTION_HANDLERS = { - [SHOW_ACTIVITY_MODAL]: (state, { modalType, modalProps }) => ({ + [SHOW_ACTIVITY_MODAL]: (state, { itemType, itemId }) => ({ ...state, - modal: { modalType, modalProps } + modal: { itemType, itemId } }), - [HIDE_ACTIVITY_MODAL]: state => ({ ...state, modal: { modalType: null, modalProps: {} } }), + [HIDE_ACTIVITY_MODAL]: state => ({ ...state, modal: { itemType: null, itemId: null } }), [CHANGE_FILTER]: (state, { filter }) => ({ ...state, filter, filterPulldown: false }), [TOGGLE_PULLDOWN]: state => ({ ...state, filterPulldown: !state.filterPulldown }), [TOGGLE_EXPIRED_REQUESTS]: state => ({ @@ -115,8 +115,8 @@ const ACTION_HANDLERS = { [SET_ACTIVITY_MODAL_CURRENCY_FILTERS]: (state, { showCurrencyFilters }) => ({ ...state, modal: { - modalType: state.modal.modalType, - modalProps: state.modal.modalProps, + itemType: state.modal.itemType, + itemId: state.modal.itemId, showCurrencyFilters } }), @@ -136,12 +136,34 @@ const showExpiredSelector = state => state.activity.showExpiredRequests const paymentsSelector = state => state.payment.payments const invoicesSelector = state => state.invoice.invoices const transactionsSelector = state => state.transaction.transactions +const modalItemTypeSelector = state => state.activity.modal.itemType +const modalItemIdSelector = state => state.activity.modal.itemId const invoiceExpired = invoice => { const expiresAt = parseInt(invoice.creation_date, 10) + parseInt(invoice.expiry, 10) return expiresAt < Date.now() / 1000 } +activitySelectors.activityModalItem = createSelector( + paymentsSelector, + invoicesSelector, + transactionsSelector, + modalItemTypeSelector, + modalItemIdSelector, + (payments, invoices, transactions, itemType, itemId) => { + switch (itemType) { + case 'INVOICE': + return invoices.find(invoice => invoice.payment_request === itemId) + case 'TRANSACTION': + return transactions.find(transaction => transaction.tx_hash === itemId) + case 'PAYMENT': + return payments.find(payment => payment.payment_hash === itemId) + default: + return null + } + } +) + // helper function that returns invoice, payment or transaction timestamp function returnTimestamp(transaction) { // if on-chain txn diff --git a/app/reducers/invoice.js b/app/reducers/invoice.js index fdf43c77..ed85d177 100644 --- a/app/reducers/invoice.js +++ b/app/reducers/invoice.js @@ -138,7 +138,7 @@ export const createdInvoice = (event, invoice) => dispatch => { dispatch(push('/')) // Set invoice modal to newly created invoice - dispatch(showActivityModal('INVOICE', { invoice })) + dispatch(showActivityModal('INVOICE', invoice.payment_request)) } export const invoiceFailed = (event, { error }) => dispatch => { diff --git a/app/routes/activity/components/components/Invoice/Invoice.js b/app/routes/activity/components/components/Invoice/Invoice.js index b76a7835..500226cc 100644 --- a/app/routes/activity/components/components/Invoice/Invoice.js +++ b/app/routes/activity/components/components/Invoice/Invoice.js @@ -11,7 +11,7 @@ import styles from '../Activity.scss' const Invoice = ({ invoice, ticker, currentTicker, showActivityModal, currencyName }) => (
showActivityModal('INVOICE', { invoice })} + onClick={() => showActivityModal('INVOICE', invoice.payment_request)} >
showActivityModal('PAYMENT', { payment })}> +
showActivityModal('PAYMENT', payment.payment_hash)} + >
diff --git a/app/routes/activity/components/components/Transaction/Transaction.js b/app/routes/activity/components/components/Transaction/Transaction.js index c5285178..46357b09 100644 --- a/app/routes/activity/components/components/Transaction/Transaction.js +++ b/app/routes/activity/components/components/Transaction/Transaction.js @@ -11,7 +11,7 @@ import styles from '../Activity.scss' const Transaction = ({ transaction, ticker, currentTicker, showActivityModal, currencyName }) => (
showActivityModal('TRANSACTION', { transaction })} + onClick={() => showActivityModal('TRANSACTION', transaction.tx_hash)} >
diff --git a/app/routes/app/containers/AppContainer.js b/app/routes/app/containers/AppContainer.js index d20c837c..aa0b0732 100644 --- a/app/routes/app/containers/AppContainer.js +++ b/app/routes/app/containers/AppContainer.js @@ -71,7 +71,11 @@ import { fetchDescribeNetwork } from 'reducers/network' import { clearError } from 'reducers/error' -import { hideActivityModal, setActivityModalCurrencyFilters } from 'reducers/activity' +import { + hideActivityModal, + setActivityModalCurrencyFilters, + activitySelectors +} from 'reducers/activity' import App from '../components/App' @@ -159,6 +163,8 @@ const mapStateToProps = state => ({ network: state.network, + activityModalItem: activitySelectors.activityModalItem(state), + currentTicker: tickerSelectors.currentTicker(state), currentCurrencyFilters: tickerSelectors.currentCurrencyFilters(state), currencyName: tickerSelectors.currencyName(state), @@ -364,8 +370,10 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { } const activityModalProps = { - modalType: stateProps.activity.modal.modalType, - modalProps: stateProps.activity.modal.modalProps, + itemType: stateProps.activity.modal.itemType, + itemId: stateProps.activity.modal.itemId, + item: stateProps.activityModalItem, + ticker: stateProps.ticker, currentTicker: stateProps.currentTicker, network: stateProps.info.network, diff --git a/test/unit/reducers/__snapshots__/activity.spec.js.snap b/test/unit/reducers/__snapshots__/activity.spec.js.snap new file mode 100644 index 00000000..c41e52d6 --- /dev/null +++ b/test/unit/reducers/__snapshots__/activity.spec.js.snap @@ -0,0 +1,241 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`reducers activityReducer should correctly changeFilter 1`] = ` +Object { + "filter": undefined, + "filterPulldown": false, + "filters": Array [ + Object { + "key": "ALL_ACTIVITY", + "name": "All", + }, + Object { + "key": "SENT_ACTIVITY", + "name": "Sent", + }, + Object { + "key": "REQUESTED_ACTIVITY", + "name": "Requested", + }, + Object { + "key": "PENDING_ACTIVITY", + "name": "Pending", + }, + ], + "modal": Object { + "itemId": null, + "itemType": null, + "showCurrencyFilters": false, + }, + "searchActive": false, + "searchText": "", +} +`; + +exports[`reducers activityReducer should correctly hideActivityModal 1`] = ` +Object { + "filter": Object { + "key": "ALL_ACTIVITY", + "name": "All Activity", + }, + "filterPulldown": false, + "filters": Array [ + Object { + "key": "ALL_ACTIVITY", + "name": "All", + }, + Object { + "key": "SENT_ACTIVITY", + "name": "Sent", + }, + Object { + "key": "REQUESTED_ACTIVITY", + "name": "Requested", + }, + Object { + "key": "PENDING_ACTIVITY", + "name": "Pending", + }, + ], + "modal": Object { + "itemId": null, + "itemType": null, + }, + "searchActive": false, + "searchText": "", +} +`; + +exports[`reducers activityReducer should correctly setActivityModalCurrencyFilters 1`] = ` +Object { + "filter": Object { + "key": "ALL_ACTIVITY", + "name": "All Activity", + }, + "filterPulldown": false, + "filters": Array [ + Object { + "key": "ALL_ACTIVITY", + "name": "All", + }, + Object { + "key": "SENT_ACTIVITY", + "name": "Sent", + }, + Object { + "key": "REQUESTED_ACTIVITY", + "name": "Requested", + }, + Object { + "key": "PENDING_ACTIVITY", + "name": "Pending", + }, + ], + "modal": Object { + "itemId": null, + "itemType": null, + "showCurrencyFilters": undefined, + }, + "searchActive": false, + "searchText": "", +} +`; + +exports[`reducers activityReducer should correctly showActivityModal 1`] = ` +Object { + "filter": Object { + "key": "ALL_ACTIVITY", + "name": "All Activity", + }, + "filterPulldown": false, + "filters": Array [ + Object { + "key": "ALL_ACTIVITY", + "name": "All", + }, + Object { + "key": "SENT_ACTIVITY", + "name": "Sent", + }, + Object { + "key": "REQUESTED_ACTIVITY", + "name": "Requested", + }, + Object { + "key": "PENDING_ACTIVITY", + "name": "Pending", + }, + ], + "modal": Object { + "itemId": undefined, + "itemType": undefined, + }, + "searchActive": false, + "searchText": "", +} +`; + +exports[`reducers activityReducer should correctly togglePulldown 1`] = ` +Object { + "filter": Object { + "key": "ALL_ACTIVITY", + "name": "All Activity", + }, + "filterPulldown": true, + "filters": Array [ + Object { + "key": "ALL_ACTIVITY", + "name": "All", + }, + Object { + "key": "SENT_ACTIVITY", + "name": "Sent", + }, + Object { + "key": "REQUESTED_ACTIVITY", + "name": "Requested", + }, + Object { + "key": "PENDING_ACTIVITY", + "name": "Pending", + }, + ], + "modal": Object { + "itemId": null, + "itemType": null, + "showCurrencyFilters": false, + }, + "searchActive": false, + "searchText": "", +} +`; + +exports[`reducers activityReducer should correctly updateSearchActive 1`] = ` +Object { + "filter": Object { + "key": "ALL_ACTIVITY", + "name": "All Activity", + }, + "filterPulldown": false, + "filters": Array [ + Object { + "key": "ALL_ACTIVITY", + "name": "All", + }, + Object { + "key": "SENT_ACTIVITY", + "name": "Sent", + }, + Object { + "key": "REQUESTED_ACTIVITY", + "name": "Requested", + }, + Object { + "key": "PENDING_ACTIVITY", + "name": "Pending", + }, + ], + "modal": Object { + "itemId": null, + "itemType": null, + "showCurrencyFilters": false, + }, + "searchActive": undefined, + "searchText": "", +} +`; + +exports[`reducers activityReducer should correctly updateSearchText 1`] = ` +Object { + "filter": Object { + "key": "ALL_ACTIVITY", + "name": "All Activity", + }, + "filterPulldown": false, + "filters": Array [ + Object { + "key": "ALL_ACTIVITY", + "name": "All", + }, + Object { + "key": "SENT_ACTIVITY", + "name": "Sent", + }, + Object { + "key": "REQUESTED_ACTIVITY", + "name": "Requested", + }, + Object { + "key": "PENDING_ACTIVITY", + "name": "Pending", + }, + ], + "modal": Object { + "itemId": null, + "itemType": null, + "showCurrencyFilters": false, + }, + "searchActive": false, + "searchText": undefined, +} +`; diff --git a/test/unit/reducers/activity.spec.js b/test/unit/reducers/activity.spec.js new file mode 100644 index 00000000..cef1e472 --- /dev/null +++ b/test/unit/reducers/activity.spec.js @@ -0,0 +1,75 @@ +import activityReducer, { + SHOW_ACTIVITY_MODAL, + HIDE_ACTIVITY_MODAL, + CHANGE_FILTER, + TOGGLE_PULLDOWN, + SET_ACTIVITY_MODAL_CURRENCY_FILTERS, + UPDATE_SEARCH_ACTIVE, + UPDATE_SEARCH_TEXT +} from 'reducers/activity' + +describe('reducers', () => { + describe('activityReducer', () => { + it('should have SHOW_ACTIVITY_MODAL', () => { + expect(SHOW_ACTIVITY_MODAL).toEqual('SHOW_ACTIVITY_MODAL') + }) + + it('should have HIDE_ACTIVITY_MODAL', () => { + expect(HIDE_ACTIVITY_MODAL).toEqual('HIDE_ACTIVITY_MODAL') + }) + + it('should have CHANGE_FILTER', () => { + expect(CHANGE_FILTER).toEqual('CHANGE_FILTER') + }) + + it('should have TOGGLE_PULLDOWN', () => { + expect(TOGGLE_PULLDOWN).toEqual('TOGGLE_PULLDOWN') + }) + + it('should have SET_ACTIVITY_MODAL_CURRENCY_FILTERS', () => { + expect(SET_ACTIVITY_MODAL_CURRENCY_FILTERS).toEqual('SET_ACTIVITY_MODAL_CURRENCY_FILTERS') + }) + + it('should have UPDATE_SEARCH_ACTIVE', () => { + expect(UPDATE_SEARCH_ACTIVE).toEqual('UPDATE_SEARCH_ACTIVE') + }) + + it('should have UPDATE_SEARCH_TEXT', () => { + expect(UPDATE_SEARCH_TEXT).toEqual('UPDATE_SEARCH_TEXT') + }) + + it('should correctly showActivityModal', () => { + expect(activityReducer(undefined, { type: SHOW_ACTIVITY_MODAL })).toMatchSnapshot() + }) + + it('should correctly hideActivityModal', () => { + expect( + activityReducer(undefined, { type: HIDE_ACTIVITY_MODAL, invoices: [1, 2] }) + ).toMatchSnapshot() + }) + + it('should correctly changeFilter', () => { + expect(activityReducer(undefined, { type: CHANGE_FILTER })).toMatchSnapshot() + }) + + it('should correctly togglePulldown', () => { + expect( + activityReducer(undefined, { type: TOGGLE_PULLDOWN, invoice: 'foo' }) + ).toMatchSnapshot() + }) + + it('should correctly setActivityModalCurrencyFilters', () => { + expect( + activityReducer(undefined, { type: SET_ACTIVITY_MODAL_CURRENCY_FILTERS }) + ).toMatchSnapshot() + }) + + it('should correctly updateSearchActive', () => { + expect(activityReducer(undefined, { type: UPDATE_SEARCH_ACTIVE })).toMatchSnapshot() + }) + + it('should correctly updateSearchText', () => { + expect(activityReducer(undefined, { type: UPDATE_SEARCH_TEXT })).toMatchSnapshot() + }) + }) +})