From f56128d2446b19be06d850ef559d92e7c35177e1 Mon Sep 17 00:00:00 2001 From: Jack Mallers Date: Tue, 1 Aug 2017 14:12:16 -0500 Subject: [PATCH] feature(modal): modal for detailed payment/invoice --- app/app.global.scss | 13 ++ app/reducers/invoice.js | 24 ++- app/reducers/payment.js | 24 ++- app/reducers/ticker.js | 3 +- app/routes/activity/components/Activity.js | 30 +++- .../components/components/Invoices.js | 83 ++++++++--- .../components/components/Invoices.scss | 47 ++++++ .../activity/components/components/Modal.js | 45 ++++++ .../components/components/Payments.js | 139 ++++++++++++------ .../components/components/Payments.scss | 43 ++++++ .../activity/containers/ActivityContainer.js | 10 +- package-lock.json | 5 + package.json | 1 + 13 files changed, 389 insertions(+), 78 deletions(-) create mode 100644 app/routes/activity/components/components/Modal.js diff --git a/app/app.global.scss b/app/app.global.scss index 2fac4bf3..aebe8940 100644 --- a/app/app.global.scss +++ b/app/app.global.scss @@ -21,4 +21,17 @@ body { -webkit-font-smoothing: antialiased; -webkit-tap-highlight-color: rgba(255,255,255,0); font-family: 'Roboto'; +} + +.ReactModal__Overlay { + transition: opacity 500ms ease-in-out; + opacity: 0; + + &--after-open { + opacity: 1; + } + + &--before-close { + opacity: 0; + } } \ No newline at end of file diff --git a/app/reducers/invoice.js b/app/reducers/invoice.js index fb92c33f..1aa72630 100644 --- a/app/reducers/invoice.js +++ b/app/reducers/invoice.js @@ -1,8 +1,11 @@ +import { createSelector } from 'reselect' import { callApi } from '../api' import { btc, usd } from '../utils' // ------------------------------------ // Constants // ------------------------------------ +export const SET_INVOICE = 'SET_INVOICE' + export const GET_INVOICE = 'GET_INVOICE' export const RECEIVE_INVOICE = 'RECEIVE_INVOICE' @@ -17,6 +20,13 @@ export const INVOICE_FAILED = 'INVOICE_FAILED' // ------------------------------------ // Actions // ------------------------------------ +export function setInvoice(invoice) { + return { + type: SET_INVOICE, + invoice + } +} + export function getInvoice() { return { type: GET_INVOICE @@ -104,6 +114,8 @@ export function invoiceFailed() { // Action Handlers // ------------------------------------ const ACTION_HANDLERS = { + [SET_INVOICE]: (state, { invoice }) => ({ ...state, invoice }), + [GET_INVOICE]: (state) => ({ ...state, invoiceLoading: true }), [RECEIVE_INVOICE]: (state, { data }) => ({ ...state, invoiceLoading: false, data }), @@ -115,13 +127,23 @@ const ACTION_HANDLERS = { [INVOICE_FAILED]: (state) => ({ ...state, invoiceLoading: false, data: null }) } +const invoiceSelectors = {} +const modalInvoiceSelector = state => state.invoice.invoice + +invoiceSelectors.invoiceModalOpen = createSelector( + modalInvoiceSelector, + invoice => invoice ? true : false +) + +export { invoiceSelectors } + // ------------------------------------ // Reducer // ------------------------------------ const initialState = { invoiceLoading: false, invoices: [], - invoice: {}, + invoice: null, data: {} } diff --git a/app/reducers/payment.js b/app/reducers/payment.js index fa2055a9..32c26730 100644 --- a/app/reducers/payment.js +++ b/app/reducers/payment.js @@ -1,8 +1,11 @@ +import { createSelector } from 'reselect' import { callApi } from '../api' import { btc } from '../utils' // ------------------------------------ // Constants // ------------------------------------ +export const SET_PAYMENT = 'SET_PAYMENT' + export const GET_PAYMENTS = 'GET_PAYMENTS' export const RECEIVE_PAYMENTS = 'RECEIVE_PAYMENTS' @@ -13,6 +16,13 @@ export const PAYMENT_FAILED = 'PAYMENT_FAILED' // ------------------------------------ // Actions // ------------------------------------ +export function setPayment(payment) { + return { + type: SET_PAYMENT, + payment + } +} + export function getPayments() { return { type: GET_PAYMENTS @@ -76,16 +86,28 @@ export const payInvoice = (payment_request) => async (dispatch) => { // Action Handlers // ------------------------------------ const ACTION_HANDLERS = { + [SET_PAYMENT]: (state, { payment }) => ({ ...state, payment }), [GET_PAYMENTS]: (state) => ({ ...state, paymentLoading: true }), [RECEIVE_PAYMENTS]: (state, { payments }) => ({ ...state, paymentLoading: false, payments }) } +const paymentSelectors = {} +const modalPaymentSelector = state => state.payment.payment + +paymentSelectors.paymentModalOpen = createSelector( + modalPaymentSelector, + payment => payment ? true : false +) + +export { paymentSelectors } + // ------------------------------------ // Reducer // ------------------------------------ const initialState = { paymentLoading: false, - payments: [] + payments: [], + payment: null } export default function paymentReducer(state = initialState, action) { diff --git a/app/reducers/ticker.js b/app/reducers/ticker.js index 501e1756..64e18d16 100644 --- a/app/reducers/ticker.js +++ b/app/reducers/ticker.js @@ -1,3 +1,4 @@ +import { createSelector } from 'reselect' import { requestTicker } from '../api' // ------------------------------------ // Constants @@ -43,7 +44,7 @@ export const fetchTicker = () => async (dispatch) => { const ACTION_HANDLERS = { [SET_CURRENCY]: (state, { currency }) => ({ ...state, currency }), [GET_TICKER]: (state) => ({ ...state, tickerLoading: true }), - [RECIEVE_TICKER]: (state, { ticker }) => ({...state, btcTicker: ticker[0] }) + [RECIEVE_TICKER]: (state, { ticker }) => ({...state, tickerLoading: false, btcTicker: ticker[0] }) } // ------------------------------------ diff --git a/app/routes/activity/components/Activity.js b/app/routes/activity/components/Activity.js index f4dd163e..12643861 100644 --- a/app/routes/activity/components/Activity.js +++ b/app/routes/activity/components/Activity.js @@ -10,7 +10,7 @@ class Activity extends Component { constructor(props, context) { super(props, context) this.state = { - tab: 1 + tab: 2 } } @@ -25,10 +25,14 @@ class Activity extends Component { const { tab } = this.state const { ticker, - invoice: { invoices, invoiceLoading }, - payment: { payments, paymentLoading } + invoice: { invoice, invoices, invoiceLoading }, + payment: { payment, payments, paymentLoading }, + setPayment, + setInvoice, + paymentModalOpen, + invoiceModalOpen } = this.props - + if (invoiceLoading || paymentLoading) { return
Loading...
} return (
@@ -62,9 +66,23 @@ class Activity extends Component { > { tab === 1 ? - + : - + }
diff --git a/app/routes/activity/components/components/Invoices.js b/app/routes/activity/components/components/Invoices.js index 8c4f2a9e..36191b08 100644 --- a/app/routes/activity/components/components/Invoices.js +++ b/app/routes/activity/components/components/Invoices.js @@ -2,28 +2,71 @@ import React, { Component } from 'react' import Moment from 'react-moment' import 'moment-timezone' +import { FaBitcoin, FaDollar } from 'react-icons/lib/fa' +import Modal from './Modal' import { btc } from '../../../../utils' import styles from './Invoices.scss' class Invoices extends Component { render() { - const { invoices, ticker } = this.props + const { + invoice, + invoices, + ticker, + setInvoice, + invoiceModalOpen + } = this.props + return ( - + } + + ) } } -export default Invoices \ No newline at end of file +export default Invoices diff --git a/app/routes/activity/components/components/Invoices.scss b/app/routes/activity/components/components/Invoices.scss index c7aeaaea..9e8bbf59 100644 --- a/app/routes/activity/components/components/Invoices.scss +++ b/app/routes/activity/components/components/Invoices.scss @@ -1,5 +1,44 @@ @import '../../../../variables.scss'; +.invoiceModal { + padding: 40px; + + h3 { + font-size: 24px; + color: $black; + font-weight: bold; + text-align: center; + margin-bottom: 10px; + } + + .paymentRequest { + text-align: center; + font-size: 8px; + } + + h1 { + text-align: center; + color: $main; + margin: 60px 30px 60px 0; + + svg { + font-size: 30px; + } + + .value { + font-size: 80px; + } + } + + .date { + text-align: center; + + time { + margin-left: 3px; + } + } +} + .invoices { width: 75%; margin: 0 auto; @@ -41,3 +80,11 @@ font-weight: bold; } } + +.invoice { + cursor: pointer; + + &:hover { + background: lighten($grey, 5%); + } +} diff --git a/app/routes/activity/components/components/Modal.js b/app/routes/activity/components/components/Modal.js new file mode 100644 index 00000000..a69dfd0b --- /dev/null +++ b/app/routes/activity/components/components/Modal.js @@ -0,0 +1,45 @@ +// @flow +import React, { Component } from 'react' +import ReactModal from 'react-modal' +import Moment from 'react-moment' +import 'moment-timezone' + +const customStyles = { + overlay: { + cursor: 'pointer' + }, + content : { + top: 'auto', + left: '20%', + right: '0', + bottom: 'auto', + width: '40%', + margin: '50px auto' + } +} + +class Modal extends Component { + render() { + const { + isOpen, + resetObject, + children + } = this.props + + return ( + resetObject(null)} + parentSelector={() => document.body} + style={customStyles} + > + {children} + + ) + } +} + +export default Modal \ No newline at end of file diff --git a/app/routes/activity/components/components/Payments.js b/app/routes/activity/components/components/Payments.js index 3e7bc8f1..e1539a8a 100644 --- a/app/routes/activity/components/components/Payments.js +++ b/app/routes/activity/components/components/Payments.js @@ -2,65 +2,112 @@ import React, { Component } from 'react' import Moment from 'react-moment' import 'moment-timezone' +import { FaBitcoin, FaDollar } from 'react-icons/lib/fa' +import Modal from './Modal' import { btc } from '../../../../utils' import styles from './Payments.scss' class Payments extends Component { render() { - const { payments, ticker } = this.props + const { + payment, + payments, + ticker, + setPayment, + paymentModalOpen + } = this.props + return ( - + + +
+ + { + ticker.currency === 'btc' ? + btc.satoshisToBtc(payment.value) + : + btc.satoshisToUsd(payment.value, ticker.btcTicker.price_usd) + } + +
+ + ) + } + + ) } } -export default Payments \ No newline at end of file +export default Payments diff --git a/app/routes/activity/components/components/Payments.scss b/app/routes/activity/components/components/Payments.scss index d20aa96c..ff906cb1 100644 --- a/app/routes/activity/components/components/Payments.scss +++ b/app/routes/activity/components/components/Payments.scss @@ -1,5 +1,48 @@ @import '../../../../variables.scss'; +.paymentModal { + padding: 40px; + + h1 { + text-align: center; + color: $main; + margin: 60px 30px 60px 0; + + svg { + font-size: 30px; + } + + .value { + font-size: 80px; + } + } + + h3 { + font-size: 14px; + text-align: center; + color: $black; + font-weight: bold; + } + + dt { + text-align: left; + float: left; + clear: left; + font-weight: 500; + padding: 20px 35px 19px 0; + color: $black; + font-weight: bold; + } + + dd { + text-align: right; + font-weight: 400; + padding: 19px 0; + margin-left: 0; + border-top: 1px solid $darkgrey; + } +} + .payments { width: 75%; margin: 0 auto; diff --git a/app/routes/activity/containers/ActivityContainer.js b/app/routes/activity/containers/ActivityContainer.js index f3feac7e..88efd907 100644 --- a/app/routes/activity/containers/ActivityContainer.js +++ b/app/routes/activity/containers/ActivityContainer.js @@ -1,9 +1,11 @@ import { connect } from 'react-redux' -import { fetchInvoices } from '../../../reducers/invoice' -import { fetchPayments } from '../../../reducers/payment' +import { fetchInvoices, setInvoice, invoiceSelectors } from '../../../reducers/invoice' +import { setPayment, fetchPayments, paymentSelectors } from '../../../reducers/payment' import Activity from '../components/Activity' const mapDispatchToProps = { + setPayment, + setInvoice, fetchPayments, fetchInvoices } @@ -12,7 +14,9 @@ const mapStateToProps = (state) => ({ activity: state.activity, payment: state.payment, invoice: state.invoice, - ticker: state.ticker + ticker: state.ticker, + paymentModalOpen: paymentSelectors.paymentModalOpen(state), + invoiceModalOpen: invoiceSelectors.invoiceModalOpen(state) }) export default connect(mapStateToProps, mapDispatchToProps)(Activity) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 20f53f20..566cc3bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12988,6 +12988,11 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, + "reselect": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz", + "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=" + }, "resolve": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", diff --git a/package.json b/package.json index 9b0c1e1f..55ff2e8d 100644 --- a/package.json +++ b/package.json @@ -203,6 +203,7 @@ "react-svg": "^2.1.21", "redux": "^3.7.1", "redux-thunk": "^2.2.0", + "reselect": "^3.0.1", "satoshi-bitcoin": "^1.0.4", "source-map-support": "^0.4.15" },