Browse Source

Merge pull request #694 from mrfelton/fix/invoice-modal-update

fix(invoice): update invoice modal once received
renovate/lint-staged-8.x
JimmyMow 6 years ago
committed by GitHub
parent
commit
2211f09f47
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      app/components/Activity/ActivityModal.js
  2. 5
      app/components/Activity/InvoiceModal.js
  3. 7
      app/components/Activity/InvoiceModal.scss
  4. 4
      app/components/Activity/PaymentModal.js
  5. 4
      app/components/Activity/TransactionModal.js
  6. 42
      app/reducers/activity.js
  7. 2
      app/reducers/invoice.js
  8. 2
      app/routes/activity/components/components/Invoice/Invoice.js
  9. 5
      app/routes/activity/components/components/Payment/Payment.js
  10. 2
      app/routes/activity/components/components/Transaction/Transaction.js
  11. 14
      app/routes/app/containers/AppContainer.js
  12. 241
      test/unit/reducers/__snapshots__/activity.spec.js.snap
  13. 75
      test/unit/reducers/activity.spec.js

17
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 (
<div className={styles.container}>
<div className={styles.closeContainer}>
@ -38,7 +39,7 @@ const ActivityModal = ({
</span>
</div>
<SpecificModal
{...modalProps}
item={item}
network={network}
ticker={ticker}
currentTicker={currentTicker}
@ -52,11 +53,9 @@ ActivityModal.propTypes = {
ticker: PropTypes.object.isRequired,
currentTicker: PropTypes.object.isRequired,
toggleCurrencyProps: PropTypes.object.isRequired,
network: PropTypes.object.isRequired,
modalType: PropTypes.string,
modalProps: PropTypes.object.isRequired,
item: PropTypes.object,
itemType: PropTypes.string,
hideActivityModal: PropTypes.func.isRequired
}

5
app/components/Activity/InvoiceModal.js

@ -15,7 +15,7 @@ import Countdown from './Countdown'
import styles from './InvoiceModal.scss'
const InvoiceModal = ({
invoice,
item: invoice,
ticker,
currentTicker,
@ -83,6 +83,7 @@ const InvoiceModal = ({
<Moment format="MM/DD/YYYY">{invoice.creation_date * 1000}</Moment>
</p>
{!invoice.settled && <p className={styles.notPaid}>Not Paid</p>}
{invoice.settled && <p className={styles.paid}>Paid</p>}
</section>
</div>
@ -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

7
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;
}
}

4
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,

4
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,

42
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

2
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 => {

2
app/routes/activity/components/components/Invoice/Invoice.js

@ -11,7 +11,7 @@ import styles from '../Activity.scss'
const Invoice = ({ invoice, ticker, currentTicker, showActivityModal, currencyName }) => (
<div
className={`${styles.container} ${!invoice.settled ? styles.unpaid : undefined}`}
onClick={() => showActivityModal('INVOICE', { invoice })}
onClick={() => showActivityModal('INVOICE', invoice.payment_request)}
>
<div className={styles.activityTypeIcon}>
<section

5
app/routes/activity/components/components/Payment/Payment.js

@ -20,7 +20,10 @@ const Payment = ({ payment, ticker, currentTicker, showActivityModal, nodes, cur
}
return (
<div className={styles.container} onClick={() => showActivityModal('PAYMENT', { payment })}>
<div
className={styles.container}
onClick={() => showActivityModal('PAYMENT', payment.payment_hash)}
>
<div className={styles.activityTypeIcon}>
<section className="hint--bottom" data-hint="Lightning payment">
<Isvg src={zap} />

2
app/routes/activity/components/components/Transaction/Transaction.js

@ -11,7 +11,7 @@ import styles from '../Activity.scss'
const Transaction = ({ transaction, ticker, currentTicker, showActivityModal, currencyName }) => (
<div
className={styles.container}
onClick={() => showActivityModal('TRANSACTION', { transaction })}
onClick={() => showActivityModal('TRANSACTION', transaction.tx_hash)}
>
<div className={styles.activityTypeIcon}>
<section className="hint--bottom" data-hint="On-chain transaction">

14
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,

241
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,
}
`;

75
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()
})
})
})
Loading…
Cancel
Save