+
{ props.children }
)
diff --git a/packages/lightning-components/Icon/index.js b/packages/lightning-components/Icon/index.js
new file mode 100644
index 000000000..b25e69d38
--- /dev/null
+++ b/packages/lightning-components/Icon/index.js
@@ -0,0 +1,43 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+import { colors, css, icons } from '../helpers'
+
+export const Icon = (props) => {
+ const styles = reactCSS({
+ 'default': {
+ icon: {
+ width: 24,
+ height: 24,
+ },
+ },
+ 'small': {
+ icon: {
+ width: 20,
+ height: 20,
+ },
+ },
+ 'large': {
+ icon: {
+ width: 48,
+ height: 48,
+ },
+ },
+ 'clickable': {
+ icon: {
+ cursor: 'pointer',
+ },
+ },
+ ...css.build('icon', 'color', _.mapKeys(colors, (v, k) => (`color-${ k }`))),
+ }, props, props.style, {
+ 'clickable': !!props.onClick,
+ 'large': props.size === 'large',
+ })
+
+ return (
+
+ { icons.find(props.name || (props.style && props.style.name)) }
+
+ )
+}
+
+export default Icon
diff --git a/packages/lightning-components/Icon/story.js b/packages/lightning-components/Icon/story.js
new file mode 100644
index 000000000..29347a2e5
--- /dev/null
+++ b/packages/lightning-components/Icon/story.js
@@ -0,0 +1,21 @@
+import React from 'react'
+import { storiesOf } from '@kadira/storybook'
+
+import Icon from './'
+
+storiesOf('Icon', module)
+ .add('`swap-horizontal` icon', () => (
+
+ ))
+ .add('`chart-bubble` icon', () => (
+
+ ))
+ .add('`n/a` icon', () => (
+
+ ))
+ .add('small icon', () => (
+
+ ))
+ .add('`teal` icon', () => (
+
+ ))
diff --git a/packages/lightning-components/Input/index.js b/packages/lightning-components/Input/index.js
index 317d81854..7d160b12f 100644
--- a/packages/lightning-components/Input/index.js
+++ b/packages/lightning-components/Input/index.js
@@ -34,7 +34,7 @@ export const Input = ({ style, large, onEnter, onKeyDown, value, placeholder,
const handleKeyDown = (e) => {
const ENTER = 13
if (e.keyCode === ENTER) {
- onEnter && onEnter()
+ onEnter && onEnter(e)
}
onKeyDown && onKeyDown(e)
}
diff --git a/packages/lightning-components/LinkWithIcon/index.js b/packages/lightning-components/LinkWithIcon/index.js
index 55f3ec90d..8216b8d27 100644
--- a/packages/lightning-components/LinkWithIcon/index.js
+++ b/packages/lightning-components/LinkWithIcon/index.js
@@ -31,7 +31,7 @@ export const LinkWithIcon = ({ onClick, label, icon, paddingBottom, color }) =>
}
LinkWithIcon.defaultProps = {
- color: 'teal',
+ color: 'blue',
}
export default LinkWithIcon
diff --git a/packages/lightning-components/Popup/index.js b/packages/lightning-components/Popup/index.js
new file mode 100644
index 000000000..29879dd28
--- /dev/null
+++ b/packages/lightning-components/Popup/index.js
@@ -0,0 +1,40 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+
+export const Popup = ({ children, visible, onClose }) => {
+ const styles = reactCSS({
+ 'default': {
+ wrap: {
+ position: 'absolute',
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0,
+ },
+ cover: {
+ position: 'absolute',
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0,
+ background: 'rgba(39, 36, 41, 0.4)',
+ },
+ box: {
+ position: 'absolute',
+ left: '50%',
+ top: '50%',
+ transform: 'translate(-50%, -50%)',
+ },
+ },
+ })
+ return visible ? (
+
+ ) : null
+}
+
+export default Popup
diff --git a/packages/lightning-components/QRCode/index.js b/packages/lightning-components/QRCode/index.js
new file mode 100644
index 000000000..a54b29e33
--- /dev/null
+++ b/packages/lightning-components/QRCode/index.js
@@ -0,0 +1,27 @@
+import React from 'react'
+import { format } from 'url'
+import qrImage from 'qr-image'
+
+export const QRCode = {
+ bitcoin: ({ address }) => {
+ const bitcoinURL = format({ protocol: 'bitcoin:', host: address })
+ const svg = qrImage.svgObject(bitcoinURL, { type: 'svg' })
+
+ return (
+
+
+
+ )
+ },
+ lightning: ({ paymentRequest }) => {
+ const svg = qrImage.svgObject(paymentRequest, { type: 'svg' })
+
+ return (
+
+
+
+ )
+ }
+}
+
+export default QRCode
diff --git a/packages/lightning-components/Select/index.js b/packages/lightning-components/Select/index.js
index 9d2046fb7..6192b2a8f 100644
--- a/packages/lightning-components/Select/index.js
+++ b/packages/lightning-components/Select/index.js
@@ -27,6 +27,12 @@ export const Media = (props) => {
color: '#777',
},
},
+ 'bare': {
+ select: {
+ boxShadow: 'none',
+ padding: 0,
+ },
+ },
...css.build('media', 'color', colors),
}, props)
diff --git a/packages/lightning-components/SidebarItem/index.js b/packages/lightning-components/SidebarItem/index.js
index 6ff0e3d24..a1ccfb1f9 100644
--- a/packages/lightning-components/SidebarItem/index.js
+++ b/packages/lightning-components/SidebarItem/index.js
@@ -25,7 +25,7 @@ export const SidebarItem = ({ color, hoverColor, hover, active, ellipsis,
},
'active': {
item: {
- color: 'teal',
+ color: 'blue',
},
},
'ellipsis': {
diff --git a/packages/lightning-components/Tab/index.js b/packages/lightning-components/Tab/index.js
index e56c7bb67..c85361a5d 100644
--- a/packages/lightning-components/Tab/index.js
+++ b/packages/lightning-components/Tab/index.js
@@ -1,7 +1,7 @@
import React from 'react'
import reactCSS, { hover as h } from 'reactcss'
-import { Link } from 'react-router'
+import { Link } from 'react-router-dom'
import { Box, Text } from '../'
diff --git a/packages/lightning-components/Tabs/story.js b/packages/lightning-components/Tabs/story.js
index 97746ad09..09afab92c 100644
--- a/packages/lightning-components/Tabs/story.js
+++ b/packages/lightning-components/Tabs/story.js
@@ -20,5 +20,5 @@ const tabs = [
storiesOf('Tabs', module)
.add('tabs', () => (
-
+
))
diff --git a/packages/lightning-components/helpers/colors.js b/packages/lightning-components/helpers/colors.js
index d59b46c55..5197b0ee5 100644
--- a/packages/lightning-components/helpers/colors.js
+++ b/packages/lightning-components/helpers/colors.js
@@ -1,6 +1,5 @@
-
export default {
- 'teal': '#59D9A4',
+ 'blue': '#4990E2',
'dark-teal': '#93B9A9',
'dark-purple': '#272429',
'orange': '#F5A623',
diff --git a/packages/lightning-components/helpers/fonts.js b/packages/lightning-components/helpers/fonts.js
index 3c13d5f55..40f9c5eb0 100644
--- a/packages/lightning-components/helpers/fonts.js
+++ b/packages/lightning-components/helpers/fonts.js
@@ -1,4 +1,3 @@
-
export default {
fontFamily: '"Roboto", "Helvetica", sans-serif',
sizes: {
diff --git a/packages/lightning-components/helpers/icons.js b/packages/lightning-components/helpers/icons.js
index ac9a112b6..a67ab0c88 100644
--- a/packages/lightning-components/helpers/icons.js
+++ b/packages/lightning-components/helpers/icons.js
@@ -1,4 +1,3 @@
-/* eslint import/prefer-default-export: 0 */
import React from 'react'
const icons = {
@@ -6,12 +5,16 @@ const icons = {
'arrow-right': ,
'arrow-right-bold-circle-outline': ,
'chart-bubble': ,
+ 'close': ,
'coin': ,
'coins': ,
+ 'currency-btc': ,
'dots-vertical': ,
'flash': ,
'history': ,
'magnify': ,
+ 'playlist-remove': ,
+ 'qrcode': ,
'radiobox-blank': ,
'radiobox-marked': ,
'settings': ,
diff --git a/packages/lightning-components/helpers/spacing.js b/packages/lightning-components/helpers/spacing.js
index a5f908fc4..30baaa7ad 100644
--- a/packages/lightning-components/helpers/spacing.js
+++ b/packages/lightning-components/helpers/spacing.js
@@ -1,4 +1,3 @@
-
export default {
none: 0,
xs: 2,
diff --git a/packages/lightning-components/index.js b/packages/lightning-components/index.js
index c855aa06e..db8c03db1 100644
--- a/packages/lightning-components/index.js
+++ b/packages/lightning-components/index.js
@@ -3,6 +3,8 @@ export { default as Icon } from './Icon'
export { default as Input } from './Input'
export { default as LinkWithIcon } from './LinkWithIcon'
export { default as Media } from './Media'
+export { default as Popup } from './Popup'
+export { default as QRCode } from './QRCode'
export { default as Select } from './Select'
export { default as Tab } from './Tab'
export { default as Text } from './Text'
diff --git a/packages/lightning-components/package.json b/packages/lightning-components/package.json
index 270b905cb..4feb5da9a 100644
--- a/packages/lightning-components/package.json
+++ b/packages/lightning-components/package.json
@@ -1,6 +1,6 @@
{
"name": "lightning-components",
- "version": "0.1.0",
+ "version": "0.1.1",
"description": "",
"main": "index.js",
"scripts": {
@@ -10,8 +10,12 @@
"license": "MIT",
"dependencies": {
"lodash": "^4.16.1",
+ "qr-image": "^3.1.0",
"react": "^15.3.2",
- "react-router": "^4.0.0-alpha.5",
+ "react-router-dom": "^4.0.0",
"reactcss": "^1.0.8"
+ },
+ "devDependencies": {
+ "@kadira/storybook": "^2.35.3"
}
}
diff --git a/packages/lightning-core/accounts/ChannelList.js b/packages/lightning-core/accounts/ChannelList.js
new file mode 100644
index 000000000..876b6be11
--- /dev/null
+++ b/packages/lightning-core/accounts/ChannelList.js
@@ -0,0 +1,57 @@
+import React from 'react'
+import _ from 'lodash'
+import reactCSS from 'reactcss'
+
+import { Icon } from 'lightning-components'
+import { LoadingIcon } from '../common'
+import ChannelListItem from './ChannelListItem'
+
+export const ChannelList = ({ channels, loading }) => {
+ const styles = reactCSS({
+ 'default': {
+ list: {
+ borderTop: '1px solid #ddd',
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ },
+ empty: {
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ color: '#bbb',
+ userSelect: 'none',
+ cursor: 'default',
+ },
+ emptyLabel: {
+ fontSize: 24,
+ paddingTop: 10,
+ },
+ },
+ })
+
+ return (
+
+ { _.map(channels, (channel, i) => (
+
+ )) }
+
+ { loading ? (
+
+
+
+ ) : null }
+
+ { !channels.length && !loading ? (
+
+ ) : null }
+
+ )
+}
+
+export default ChannelList
diff --git a/packages/lightning-core/accounts/ChannelListItem.js b/packages/lightning-core/accounts/ChannelListItem.js
new file mode 100644
index 000000000..4365fd531
--- /dev/null
+++ b/packages/lightning-core/accounts/ChannelListItem.js
@@ -0,0 +1,186 @@
+import React from 'react'
+import reactCSS, { handleHover } from 'reactcss'
+import { remote } from 'electron'
+import { connect } from 'react-redux'
+import { actions as notificationActions } from 'lightning-notifications'
+import { actions as accountsActions } from '../accounts'
+import { Box, Icon } from 'lightning-components'
+import { Popup, actions as popupActions } from 'lightning-popup'
+import { actions } from './reducer'
+import { Prompt } from '../common'
+import { Money, MoneySign } from '../common'
+import { withRouter } from 'react-router'
+import { store } from 'lightning-store'
+
+const { Menu, MenuItem } = remote
+
+export const ChannelListItem = ({ id, capacity, currency, localBalance, remoteBalance,
+ active, status, hover, channelPoint, onShowPopup, onClosePopup, onCloseChannel,
+ onSuccess, onFetchChannels }) => {
+ const pending = status === 'pending-open'
+ || status === 'pending-closing'
+ || status === 'pending-force-closing'
+
+ const styles = reactCSS({
+ 'default': {
+ channel: {
+ borderBottom: '1px solid #ddd',
+ paddingTop: 20,
+ paddingBottom: 20,
+ },
+ split: {
+ display: 'flex',
+ justifyContent: 'space-between',
+ marginBottom: 7,
+ },
+ id: {
+ color: '#333',
+ fontSize: 20,
+ display: 'flex',
+ },
+ closeLabel: {
+ color: '#ce5c6a',
+ marginLeft: 10,
+ display: 'none',
+ height: 20,
+ cursor: 'pointer',
+ },
+ active: {
+ color: '#4990e2',
+ marginRight: 10,
+ },
+ status: {
+ fontSize: 13,
+ textTransform: 'uppercase',
+ color: '#999',
+ },
+ local: {
+ fontSize: 16,
+ color: '#4990E2',
+ },
+ remote: {
+ fontSize: 16,
+ color: '#666',
+ },
+ bar: {
+ borderRadius: 2,
+ background: 'lighter-gray',
+ marginTop: 10,
+ },
+ percent: {
+ background: 'blue',
+ height: 12,
+ borderRadius: 2,
+ },
+ },
+ 'hover': {
+ closeLabel: {
+ display: 'inline-block',
+ },
+ },
+ 'pending': {
+ id: {
+ color: '#999',
+ },
+ local: {
+ color: '#999',
+ },
+ remote: {
+ color: '#999',
+ },
+ percent: {
+ background: 'light-gray',
+ },
+ },
+ }, { hover, pending })
+
+ const PROMPT = `CHANNEL_LIST/PROMPT-${ channelPoint }`
+
+ // eslint-disable-next-line
+ const close = ({ channelPoint, force }) => {
+ const call = onCloseChannel({ channelPoint, force })
+ call.on('data', () => {
+ onSuccess('Channel Closed')
+ onFetchChannels()
+ })
+ call.on('error', err => onSuccess(err.message))
+ }
+
+ const showPopupOrClose = () =>
+ (active ? close({ channelPoint }) : onShowPopup(PROMPT))
+ const menu = new Menu()
+ menu.append(new MenuItem({ label: 'Close Channel', click() { showPopupOrClose() } }))
+ const handleMenu = () => menu.popup(remote.getCurrentWindow())
+ const handleClose = () => {
+ close({ channelPoint, force: true })
+ onClosePopup(PROMPT)
+ }
+ const handleCancel = () => onClosePopup(PROMPT)
+
+ const width = `${ (localBalance / capacity) * 100 }%`
+ const title = {
+ 'open': `CID: ${ id }`,
+ 'pending-open': 'OPENING',
+ 'pending-closing': 'CLOSING',
+ 'pending-force-closing': 'CLOSING',
+ }[status]
+
+ return (
+
+
+
+ { title }
+ { !pending && (
+
+
+
+ ) }
+
+
+ { active ? (
+ active
+ ) : null }
+ { status }
+
+
+
+
+
My Balance:
+
Available to Receive:
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default connect(
+ state => ({
+ serverRunning: store.getServerRunning(state),
+ isSynced: store.getSyncedToChain(state),
+ pubkey: store.getAccountPubkey(state),
+ currency: store.getCurrency(state),
+ balances: store.getAccountBalances(state),
+ }), {
+ onShowPopup: popupActions.onOpen,
+ onClosePopup: popupActions.onClose,
+ onCloseChannel: actions.startCloseChannel,
+ onSuccess: notificationActions.addNotification,
+ onFetchChannels: accountsActions.fetchChannels,
+ onfetchAccount: accountsActions.fetchAccount,
+ onfetchBalances: accountsActions.fetchBalances,
+ },
+)(handleHover(ChannelListItem))
diff --git a/packages/lightning-core/accounts/CreateChannelPage.js b/packages/lightning-core/accounts/CreateChannelPage.js
new file mode 100644
index 000000000..817927694
--- /dev/null
+++ b/packages/lightning-core/accounts/CreateChannelPage.js
@@ -0,0 +1,64 @@
+import React from 'react'
+import { connect } from 'react-redux'
+import { Form } from 'lightning-forms'
+import { actions } from './reducer'
+import { remote } from 'electron'
+import { CurrencyInput, Head, Input, Page } from '../common'
+
+const { Menu, MenuItem } = remote
+
+export const CreateChannelPage = ({ createChannel, push }) => {
+ const fields = [
+ {
+ name: 'ip',
+ placeholder: 'Pubkey@HostIP',
+ required: true,
+ component: Input,
+ },
+ {
+ name: 'amount',
+ placeholder: 'Amount',
+ required: true,
+ component: CurrencyInput,
+ },
+ ]
+
+ const menu = new Menu()
+ menu.append(new MenuItem({ label: 'Paste', role: 'paste' }))
+ const handleMenu = () => menu.popup(remote.getCurrentWindow())
+
+ const handleSuccess = ({ ip, amount }, clear) => {
+ createChannel({ ip, amount })
+ .then(() => {
+ clear()
+ push('/accounts')
+ })
+ // eslint-disable-next-line no-console
+ .catch(console.error)
+ }
+
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default connect(
+ () => ({}), {
+ createChannel: actions.createChannel,
+ push: actions.push,
+ },
+)(CreateChannelPage)
diff --git a/packages/lightning-core/accounts/Wallet.js b/packages/lightning-core/accounts/Wallet.js
new file mode 100644
index 000000000..bdcd204fe
--- /dev/null
+++ b/packages/lightning-core/accounts/Wallet.js
@@ -0,0 +1,126 @@
+import React from 'react'
+import _ from 'lodash'
+import reactCSS from 'reactcss'
+import { connect } from 'react-redux'
+import { withRouter } from 'react-router'
+import { actions as accountActions } from '../accounts'
+import { store } from 'lightning-store'
+import { Money, MoneySign } from '../common'
+import { total } from '../helpers'
+import { Text } from 'lightning-components'
+
+export const Wallet = ({ pubkey, currency, balances }) => {
+ const styles = reactCSS({
+ 'default': {
+ bg: {
+ background: '#4990E2',
+ color: '#fff',
+ padding: 30,
+ paddingBottom: 20,
+ },
+ title: {
+ color: 'rgba(0,0,0,0.4)',
+ fontSize: 24,
+ userSelect: 'none',
+ cursor: 'default',
+ },
+ details: {
+ display: 'flex',
+ justifyContent: 'space-between',
+ alignItems: 'flex-end',
+ },
+ total: {
+
+ },
+ amount: {
+ fontSize: 32,
+ marginBottom: 10,
+ },
+ address: {
+ fontSize: 16,
+ color: 'rgba(0,0,0,0.4)',
+ minWidth: 300,
+ wordBreak: 'break-word',
+ marginRight: 20,
+ marginBottom: 10,
+ },
+ breakdown: {
+ fontSize: 16,
+ },
+ item: {
+ display: 'flex',
+ marginBottom: 10,
+ },
+ label: {
+ color: 'rgba(0,0,0,0.4)',
+ whiteSpace: 'nowrap',
+ marginRight: 10,
+ width: 90,
+ userSelect: 'none',
+ cursor: 'default',
+ },
+ count: {
+ flex: 1,
+ color: 'reba(255,255,255,0.9)',
+ whiteSpace: 'nowrap',
+ },
+ },
+ })
+
+ const breakdown = [
+ {
+ label: 'On Chain',
+ amount: balances.wallet,
+ }, {
+ label: 'In Channels',
+ amount: balances.channel,
+ },
+ ]
+
+ if (balances.limbo) {
+ breakdown.push({
+ label: 'In Limbo',
+ amount: balances.limbo,
+ })
+ }
+
+ return (
+
+
Your Wallet
+
+
+
+
+
+
Pubkey: { pubkey }
+
+
+
+ { _.map(breakdown, (item, i) => (
+
+
+ { item.label }
+
+
+
+
+
+ )) }
+
+
+
+
+ )
+}
+export default withRouter(connect(
+ state => ({
+ serverRunning: store.getServerRunning(state),
+ isSynced: store.getSyncedToChain(state),
+ pubkey: store.getAccountPubkey(state),
+ currency: store.getCurrency(state),
+ balances: store.getAccountBalances(state),
+ }), {
+ fetchAccount: accountActions.fetchAccount,
+ fetchBalances: accountActions.fetchBalances,
+ },
+)(Wallet))
diff --git a/packages/lightning-core/accounts/index.js b/packages/lightning-core/accounts/index.js
new file mode 100644
index 000000000..2a4a583d5
--- /dev/null
+++ b/packages/lightning-core/accounts/index.js
@@ -0,0 +1,73 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+import { connect } from 'react-redux'
+import { store } from 'lightning-store'
+import { Link } from 'react-router-dom'
+import { actions } from './reducer'
+
+import { Head, Page } from '../common'
+import Wallet from './Wallet'
+import ChannelList from './ChannelList'
+
+export class Accounts extends React.Component {
+ componentDidMount() {
+ this.props.fetchBalances()
+ this.props.onMount()
+ }
+
+ render() {
+ const { pubkey, balances, channels, loading } = this.props
+ const styles = reactCSS({
+ default: {
+ page: {
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ },
+ link: {
+ fontSize: 12,
+ textTransform: 'uppercase',
+ textDecoration: 'none',
+ color: '#4990E2',
+ },
+ },
+ })
+ const createChannel = (
+ Create Channel
+ )
+ return (
+
+ )
+ }
+}
+
+export default connect(
+ state => ({
+ channels: store.getChannels(state),
+ loading: store.getChannelsLoading(state),
+ balances: store.getAccountBalances(state),
+ pubkey: store.getAccountPubkey(state),
+ }), {
+ onMount: actions.fetchChannels,
+ fetchBalances: actions.fetchBalances,
+ },
+)(Accounts)
+
+export { default as reducer, actions, selectors } from './reducer'
+export { default as CreateChannelPage } from './CreateChannelPage'
diff --git a/packages/lightning-core/accounts/reducer.js b/packages/lightning-core/accounts/reducer.js
new file mode 100644
index 000000000..0a5cc8364
--- /dev/null
+++ b/packages/lightning-core/accounts/reducer.js
@@ -0,0 +1,273 @@
+import _ from 'lodash'
+import { GRPC, SERVER_RUNNING } from 'redux-grpc-middleware'
+import { actions as notificationActions } from 'lightning-notifications'
+
+export const FETCH_ACCOUNT = 'ACCOUNTS/FETCH_ACCOUNT'
+export const FETCH_BALANCES = 'ACCOUNTS/FETCH_BALANCES'
+export const SET_BALANCES = 'ACCOUNTS/SET_BALANCES'
+export const REQUEST_CHANNELS = 'ACCOUNTS/REQUEST_CHANNELS'
+export const FETCH_CHANNELS = 'ACCOUNTS/FETCH_CHANNELS'
+export const FETCH_CHANNELS_FAILURE = 'ACCOUNTS/FETCH_CHANNELS_FAILURE'
+export const LIST_PEERS = 'ACCOUNTS/LIST_PEERS'
+export const OPEN_CHANNEL = 'ACCOUNTS/OPEN_CHANNEL'
+export const CONNECT_PEER = 'ACCOUNTS/CONNECT_PEER'
+export const START_CLOSING_CHANNEL = 'ACCOUNTS/START_CLOSING_CHANNEL'
+export const CLOSE_CHANNEL = 'ACCOUNTS/CLOSE_CHANNEL'
+export const PENDING_CHANNELS = 'ACCOUNTS/PENDING_CHANNELS'
+export const FETCH_ACCOUNT_FAILURE = 'ACCOUNTS/FETCH_ACCOUNT_ERROR'
+
+const initialState = {
+ pubkey: '',
+ isSynced: true,
+ serverRunning: false,
+ currency: 'satoshi',
+ balances: {
+ wallet: 0,
+ channel: 0,
+ },
+ channels: [],
+ pendingChannels: [],
+ loadingChannels: false,
+}
+
+export default (state = initialState, action) => {
+ switch (action.type) {
+ case SERVER_RUNNING:
+ return { ...state, serverRunning: true }
+ case REQUEST_CHANNELS:
+ return { ...state, loadingChannels: true }
+ case FETCH_ACCOUNT:
+ return { ...state, pubkey: action.pubkey, isSynced: action.isSynced }
+ case FETCH_ACCOUNT_FAILURE:
+ return { ...state, isSynced: false }
+ case SET_BALANCES:
+ return { ...state, balances: { ...state.balances, ...action.balances } }
+ case PENDING_CHANNELS:
+ return {
+ ...state,
+ pendingChannels: action.pendingChannels,
+ balances: {
+ ...state.balances,
+ limbo: action.limboBalance,
+ },
+ loadingChannels: false,
+ }
+ case FETCH_CHANNELS:
+ return {
+ ...state,
+ channels: action.channels,
+ loadingChannels: false,
+ }
+ case START_CLOSING_CHANNEL:
+ return {
+ ...state,
+ channels: _.map(state.channels, (c) => {
+ if (c.channelPoint === action.channelPoint) {
+ return {
+ ...c,
+ status: 'closing',
+ }
+ }
+ return c
+ }),
+ }
+ case FETCH_CHANNELS_FAILURE:
+ return { ...state, channels: [], loadingChannels: false }
+ default: return state
+ }
+}
+
+export const actions = {
+ fetchAccount: () => ({
+ [GRPC]: {
+ method: 'getInfo',
+ types: [null, FETCH_ACCOUNT, FETCH_ACCOUNT_FAILURE],
+ schema: account => ({
+ pubkey: account.identity_pubkey,
+ isSynced: account.synced_to_chain,
+ }),
+ },
+ }),
+ fetchBalances: () => (dispatch) => {
+ Promise.all([
+ dispatch({
+ [GRPC]: {
+ method: 'walletBalance',
+ schema: wallet => ({
+ wallet: parseInt(wallet.balance, 10), // To SAT,
+ }),
+ },
+ }),
+ dispatch({
+ [GRPC]: {
+ method: 'channelBalance',
+ schema: channel => ({
+ channel: parseInt(channel.balance, 10),
+ }),
+ },
+ }),
+ ])
+ .then((results) => {
+ const account = _.reduce(results, _.extend)
+ dispatch({
+ type: SET_BALANCES,
+ balances: {
+ wallet: account.wallet,
+ channel: account.channel,
+ },
+ })
+ })
+ // eslint-disable-next-line no-console
+ .catch(console.error)
+ },
+ pendingChannels: () => ({
+ [GRPC]: {
+ method: 'pendingChannels',
+ types: [null, PENDING_CHANNELS, FETCH_CHANNELS_FAILURE],
+ schema: (data) => {
+ const decorateChannels = (channels, transform) =>
+ _.map(channels, channel => ({
+ remotePubkey: channel.remote_node_pub,
+ capacity: channel.capacity,
+ localBalance: channel.local_balance,
+ remoteBalance: channel.remote_balance,
+ channelPoint: channel.channel_point,
+ ...transform(channel),
+ }))
+
+ return {
+ pendingChannels: [
+ ...decorateChannels(data.pending_open_channels, () => ({ status: 'pending-open' })),
+ ...decorateChannels(data.pending_closing_channels, () => ({ status: 'pending-closing' })),
+ ...decorateChannels(data.pending_force_closing_channels, () => ({ status: 'pending-force-closing' })),
+ ],
+ limboBalance: parseInt(data.total_limbo_balance, 0),
+ }
+ },
+ },
+ }),
+ listChannels: () => ({
+ [GRPC]: {
+ method: 'listChannels',
+ types: [REQUEST_CHANNELS, FETCH_CHANNELS, FETCH_CHANNELS_FAILURE],
+ schema: data => ({
+ channels: _.map(data.channels, channel => ({
+ remotePubkey: channel.remote_pubkey,
+ id: channel.chan_id,
+ capacity: channel.capacity,
+ localBalance: channel.local_balance,
+ remoteBalance: channel.remote_balance,
+ channelPoint: channel.channel_point,
+ active: channel.active,
+ status: 'open',
+ })),
+ }),
+ },
+ }),
+ fetchChannels: () => (dispatch) => {
+ dispatch(actions.listChannels())
+ dispatch(actions.pendingChannels())
+ },
+ listPeers: () => ({
+ [GRPC]: {
+ method: 'listPeers',
+ types: LIST_PEERS,
+ schema: list => ({
+ peers: list.peers || {},
+ }),
+ },
+ }),
+ openChannel: ({ pubkey, amount }) => ({
+ [GRPC]: {
+ method: 'openChannel',
+ types: OPEN_CHANNEL,
+ params: {
+ node_pubkey: new Buffer(pubkey, 'hex'),
+ local_funding_amount: amount,
+ num_confs: 1,
+ },
+ stream: true,
+ },
+ }),
+ connectPeer: ({ host, pubkey }) => ({
+ [GRPC]: {
+ method: 'connectPeer',
+ body: {
+ addr: { host, pubkey },
+ },
+ types: CONNECT_PEER,
+ },
+ }),
+ createChannel: ({ ip, amount }) => (dispatch) => {
+ return new Promise((resolve, reject) => {
+ const [pubkey, host] = ip && ip.split('@')
+
+ const rejectError = (err) => {
+ dispatch(notificationActions.addNotification(err.message))
+ reject(err.message)
+ }
+
+ const handleResolve = () => {
+ dispatch(notificationActions.addNotification('Opening Channel'))
+ resolve()
+ }
+
+ dispatch(actions.listPeers())
+ .then(({ peers }) => {
+ const peer = _.find(peers, { pub_key: pubkey })
+
+ if (peer) {
+ const call = dispatch(actions.openChannel({ pubkey, amount }))
+ call.on('data', handleResolve)
+ call.on('error', rejectError)
+ } else {
+ dispatch(actions.connectPeer({ host, pubkey }))
+ .then(() => {
+ const call = dispatch(actions.openChannel({ pubkey, amount }))
+ call.on('data', handleResolve)
+ call.on('error', rejectError)
+ })
+ .catch(rejectError)
+ }
+ })
+ .catch(rejectError)
+ })
+ },
+ startCloseChannel: params => (dispatch) => {
+ dispatch({ type: START_CLOSING_CHANNEL, channelPoint: params.channelPoint })
+ return dispatch(actions.closeChannel(params))
+ },
+ closeChannel: ({ channelPoint, force = false }) => {
+ const txid = channelPoint.split(':')[0]
+ const index = channelPoint.split(':')[1]
+ return {
+ [GRPC]: {
+ method: 'closeChannel',
+ types: CLOSE_CHANNEL,
+ params: {
+ channel_point: {
+ funding_txid: new Buffer(txid, 'hex').reverse(),
+ output_index: parseInt(index, 10),
+ },
+ force,
+ },
+ stream: true,
+ },
+ }
+ },
+ push: (...args) =>
+ ({ type: '@@router/CALL_HISTORY_METHOD', payload: { method: 'push', args } }),
+}
+
+export const selectors = {
+ getSyncedToChain: state => state.isSynced,
+ getServerRunning: state => state.serverRunning,
+ getAccountPubkey: state => state.pubkey,
+ getCurrency: state => state.currency,
+ getAccountBalances: state => state.balances,
+ getChannels: (state) => {
+ const channels = [...state.channels, ...state.pendingChannels]
+ return channels.length ? channels : []
+ },
+ getChannelsLoading: state => state.loadingChannels,
+}
diff --git a/packages/lightning-core/common/CurrencyInput.js b/packages/lightning-core/common/CurrencyInput.js
new file mode 100644
index 000000000..90271991b
--- /dev/null
+++ b/packages/lightning-core/common/CurrencyInput.js
@@ -0,0 +1,36 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+
+import Input from './Input'
+import { enforceNumbers } from '../helpers/currencies'
+
+export const CurrencyInput = (props) => {
+ const styles = reactCSS({
+ 'default': {
+ changer: {
+ marginTop: 10,
+ marginBottom: 10,
+ borderLeft: '1px solid #ddd',
+ paddingLeft: 15,
+ paddingRight: 15,
+ display: 'flex',
+ alignItems: 'center',
+ color: '#999',
+ },
+ },
+ })
+
+ const changer = (
+ SAT
+ )
+
+ return (
+
+ )
+}
+
+export default CurrencyInput
diff --git a/packages/lightning-core/common/Head.js b/packages/lightning-core/common/Head.js
new file mode 100644
index 000000000..a0b337a0a
--- /dev/null
+++ b/packages/lightning-core/common/Head.js
@@ -0,0 +1,40 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+
+export const Head = ({ title, body, right }) => {
+ const styles = reactCSS({
+ 'default': {
+ head: {
+ paddingBottom: 30,
+ paddingRight: 30,
+ userSelect: 'none',
+ cursor: 'default',
+ },
+ title: {
+ fontSize: 24,
+ color: '#666',
+ paddingBottom: 10,
+ display: 'flex',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ },
+ body: {
+ fontSize: 16,
+ lineHeight: '21px',
+ color: '#999',
+ },
+ },
+ })
+
+ return (
+
+
+ { title }
+ { right }
+
+
{ body }
+
+ )
+}
+
+export default Head
diff --git a/packages/lightning-core/common/InfiniteScroll.js b/packages/lightning-core/common/InfiniteScroll.js
new file mode 100644
index 000000000..7de302639
--- /dev/null
+++ b/packages/lightning-core/common/InfiniteScroll.js
@@ -0,0 +1,52 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+
+import Infinite from 'react-infinite'
+
+export class InfiniteScroll extends React.Component {
+ state = {
+ height: 300,
+ }
+
+ componentDidMount() {
+ // eslint-disable-next-line react/no-did-mount-set-state
+ this.setState({ height: this.outside.offsetHeight - 30 })
+ }
+
+ componentWillReceiveProps() {
+ this.setState({ height: this.outside.offsetHeight - 30 })
+ }
+
+ render() {
+ const { children, startAtBottom, insideStyles, elementHeight } = this.props
+
+ const styles = reactCSS({
+ default: {
+ wrap: {
+ flex: 1,
+ },
+ },
+ })
+
+ return (
+ (this.outside = wrap) }>
+
+ { children }
+
+
+ )
+ }
+}
+
+InfiniteScroll.defaultProps = {
+ startAtBottom: false,
+ insideStyles: {},
+ elementHeight: 15,
+}
diff --git a/packages/lightning-core/common/Input.js b/packages/lightning-core/common/Input.js
new file mode 100644
index 000000000..a672e7b27
--- /dev/null
+++ b/packages/lightning-core/common/Input.js
@@ -0,0 +1,93 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+
+export class Input extends React.Component {
+ state = {
+ focused: false,
+ }
+
+ handleFocus = () => this.setState({ focused: true })
+ handleBlur = () => this.setState({ focused: false })
+ handleClick = () => {
+ const { selectOnClick, copyOnClick, onCopy, onClick } = this.props
+ if (copyOnClick) {
+ this.input.select()
+
+ try {
+ const wasCopied = document.execCommand('copy')
+ wasCopied && onCopy && onCopy()
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.log('Error Copying to Clipboard:', error)
+ }
+ }
+ selectOnClick && this.input.select()
+ onClick && onClick()
+ }
+
+ render() {
+ const { name, right, left, type, placeholder, value, sanitizeReturn,
+ onChange, outlineColor, fullWidth, disabled } = this.props
+ const styles = reactCSS({
+ 'default': {
+ bg: {
+ backgroundColor: '#fff',
+ boxShadow: `0 0 2px ${ outlineColor }, 0 2px 4px ${ outlineColor }`,
+ borderRadius: 2,
+ height: 54,
+ display: 'flex',
+ alignItems: 'stretch',
+ maxWidth: fullWidth ? null : 350,
+ fontSize: 16,
+ flex: 1,
+
+ transition: 'box-shadow 100ms ease-out',
+ },
+ input: {
+ background: 'none',
+ flex: 1,
+ border: 'none',
+ outline: 'none',
+ fontSize: 16,
+ paddingLeft: 20,
+ color: '#333',
+ },
+ },
+ 'focused': {
+ bg: {
+ boxShadow: '0 0 2px rgba(0,0,0,0.2), 0 4px 8px rgba(0,0,0,0.2)',
+ },
+ },
+ }, { focused: this.state.focused })
+
+ const handleChange = ({ target }) => onChange({
+ [target.name]: sanitizeReturn ? sanitizeReturn(target.value) : target.value,
+ })
+
+ return (
+
+ { left || null }
+ (this.input = input) }
+ name={ name }
+ type={ type }
+ placeholder={ placeholder }
+ value={ value }
+ disabled={ disabled }
+ onChange={ handleChange }
+ onKeyPress= { this.props.onKeyPress }
+ onFocus={ this.handleFocus }
+ onBlur={ this.handleBlur }
+ />
+ { right || null }
+
+ )
+ }
+}
+
+Input.defaultProps = {
+ outlineColor: 'rgba(0, 0, 0, 0.12)',
+}
+
+export default Input
diff --git a/packages/lightning-core/common/LoadingIcon.js b/packages/lightning-core/common/LoadingIcon.js
new file mode 100644
index 000000000..b77bf52b2
--- /dev/null
+++ b/packages/lightning-core/common/LoadingIcon.js
@@ -0,0 +1,21 @@
+import React from 'react'
+
+export const LoadingIcon = () => {
+ return (
+
+ )
+}
diff --git a/packages/lightning-core/common/Money.js b/packages/lightning-core/common/Money.js
new file mode 100644
index 000000000..7ae236a39
--- /dev/null
+++ b/packages/lightning-core/common/Money.js
@@ -0,0 +1,26 @@
+import React from 'react'
+
+import { currencies } from '../helpers'
+
+export const Money = ({ currency, amount, sign }) => {
+ const money = currencies.find(currency)
+
+ return (
+
+ { sign ? `${ money.sign } ` : null }
+ { money.format(amount) }
+
+ )
+}
+
+export const MoneyCode = ({ currency }) => {
+ const money = currencies.find(currency)
+
+ return { money.code }
+}
+
+export const MoneySign = ({ currency }) => {
+ const money = currencies.find(currency)
+
+ return { money.sign }
+}
diff --git a/packages/lightning-core/components/nav/NavFooter.js b/packages/lightning-core/common/NavFooter.js
similarity index 56%
rename from packages/lightning-core/components/nav/NavFooter.js
rename to packages/lightning-core/common/NavFooter.js
index 4a6aa3ab6..6845ee7a5 100644
--- a/packages/lightning-core/components/nav/NavFooter.js
+++ b/packages/lightning-core/common/NavFooter.js
@@ -2,11 +2,11 @@ import React from 'react'
import { Box, Media, Text } from 'lightning-components'
import NavFooterAccount from './NavFooterAccount'
-import { Money, MoneySign } from '../common'
+import { Money, MoneySign } from './'
-import { total } from '../../helpers/wallet'
+import { total } from '../helpers/wallet'
-export const NavFooter = ({ currency, amount, identity, onClickAccount, account }) => {
+export const NavFooter = ({ pubkey, currency, balances, onClickAccount }) => {
return (
@@ -15,11 +15,14 @@ export const NavFooter = ({ currency, amount, identity, onClickAccount, account
left={ }
>
-
+
-
+
)
}
diff --git a/packages/lightning-core/components/nav/NavFooterAccount.js b/packages/lightning-core/common/NavFooterAccount.js
similarity index 69%
rename from packages/lightning-core/components/nav/NavFooterAccount.js
rename to packages/lightning-core/common/NavFooterAccount.js
index 4c88652f2..f5c74b002 100644
--- a/packages/lightning-core/components/nav/NavFooterAccount.js
+++ b/packages/lightning-core/common/NavFooterAccount.js
@@ -1,12 +1,12 @@
import React from 'react'
import { hover as h } from 'reactcss'
-import { Link } from 'react-router'
+import { Link } from 'react-router-dom'
import { SidebarItem } from 'lightning-components'
-export const NavFooterAccount = ({ onClick, identity, hover }) => {
+export const NavFooterAccount = ({ identity, hover }) => {
return (
-
+
{
+export const NavLinks = ({ onChange }) => {
const links = [
{
icon: 'coin',
- label: 'Send / Request',
- id: 'payment',
+ label: 'Pay',
+ id: 'pay',
},
{
- icon: 'wallet',
- label: 'Your Wallets',
- id: 'wallets',
+ icon: 'coin',
+ label: 'Request',
+ id: 'request',
},
{
+ icon: 'wallet',
+ label: 'Channels',
+ id: 'accounts',
+ }, {
icon: 'swap-horizontal',
label: 'Transactions',
id: 'transactions',
- },
- {
- icon: 'chart-bubble',
- label: 'Channels',
- id: 'channels',
+ }, {
+ icon: 'settings',
+ label: 'Advanced',
+ id: 'settings',
},
]
@@ -33,7 +36,6 @@ export const NavLinks = ({ active, onChange }) => {
)) }
diff --git a/packages/lightning-core/components/nav/NavLinksItem.js b/packages/lightning-core/common/NavLinksItem.js
similarity index 62%
rename from packages/lightning-core/components/nav/NavLinksItem.js
rename to packages/lightning-core/common/NavLinksItem.js
index 7044648f0..dd38f08d7 100644
--- a/packages/lightning-core/components/nav/NavLinksItem.js
+++ b/packages/lightning-core/common/NavLinksItem.js
@@ -1,16 +1,16 @@
import React from 'react'
import { hover as h } from 'reactcss'
-import { Link } from 'react-router'
+import { Link, withRouter } from 'react-router-dom'
import { SidebarItem } from 'lightning-components'
-export const NavLinksItem = ({ id, icon, label, active, hover }) => {
+export const NavLinksItem = ({ id, icon, label, hover, location }) => {
return (
{
)
}
-export default h(NavLinksItem)
+export default withRouter(h(NavLinksItem))
diff --git a/packages/lightning-core/common/Page.js b/packages/lightning-core/common/Page.js
new file mode 100644
index 000000000..f46e4bcd0
--- /dev/null
+++ b/packages/lightning-core/common/Page.js
@@ -0,0 +1,8 @@
+import React from 'react'
+
+export const Page = ({ children }) =>
+
+ { children }
+
+
+export default Page
diff --git a/packages/lightning-core/common/Prompt.js b/packages/lightning-core/common/Prompt.js
new file mode 100644
index 000000000..3d8921c74
--- /dev/null
+++ b/packages/lightning-core/common/Prompt.js
@@ -0,0 +1,69 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+
+export const Prompt = ({ title, prompt, acceptLabel, cancelLabel, onAccept,
+ onCancel }) => {
+ const styles = reactCSS({
+ default: {
+ prompt: {
+ background: '#fff',
+ borderRadius: 2,
+ width: 400,
+ padding: 20,
+ fontSize: 16,
+ lineHeight: '22px',
+ color: '#666',
+ },
+ promptTitle: {
+ fontSize: 24,
+ marginBottom: 15,
+ color: '#333',
+ },
+ promptActions: {
+ marginTop: 15,
+ display: 'flex',
+ justifyContent: 'flex-end',
+ },
+ button: {
+ height: 44,
+ display: 'flex',
+ alignItems: 'center',
+ paddingLeft: 15,
+ paddingRight: 15,
+ borderRadius: 3,
+ cursor: 'pointer',
+ textTransform: 'uppercase',
+ },
+ accept: {
+ background: '#DA7783',
+ marginRight: 15,
+ color: '#fff',
+ },
+ cancel: {
+ background: '#eee',
+ color: '#666',
+ },
+ },
+ })
+
+ return (
+
+ { title ?
{ title }
: null }
+ { prompt }
+
+
+ { acceptLabel }
+
+
+ { cancelLabel }
+
+
+
+ )
+}
diff --git a/packages/lightning-core/common/Sidebar.js b/packages/lightning-core/common/Sidebar.js
new file mode 100644
index 000000000..fd9804e93
--- /dev/null
+++ b/packages/lightning-core/common/Sidebar.js
@@ -0,0 +1,102 @@
+/* eslint-disable no-console, react/no-danger */
+import React from 'react'
+import reactCSS from 'reactcss'
+import { connect } from 'react-redux'
+import { withRouter } from 'react-router'
+import { store } from 'lightning-store'
+
+import { Box, Text } from 'lightning-components'
+import { actions as accountActions } from '../accounts'
+import NavLinks from './NavLinks'
+import NavFooter from './NavFooter'
+
+export class Sidebar extends React.Component {
+ componentDidMount() {
+ this.props.fetchAccount()
+ .catch(console.error)
+ this.props.location.pathname !== '/accounts' && this.props.fetchBalances()
+ }
+
+ render() {
+ const { navigateToSubpage, currency, pubkey, balances, isSynced,
+ serverRunning } = this.props
+ const styles = reactCSS({
+ 'default': {
+ sidebar: {
+ direction: 'column',
+ spread: true,
+ flex: 1,
+ },
+ section: {
+ padding: 'small',
+ },
+ synced: {
+ background: 'blue',
+ direction: 'column',
+ align: 'center',
+ verticalAlign: 'center',
+ marginLeft: -7,
+ marginTop: 7,
+ marginRight: -7,
+ marginBottom: -7,
+ borderBottomLeftRadius: 4,
+ height: 34,
+ },
+ syncedText: {
+ color: 'black',
+ size: 'small',
+ },
+ },
+ })
+
+ return (
+
+
+
+
+
+ { pubkey ? (
+
+ ) : null }
+
+ { serverRunning && isSynced ? null : (
+
+
+ Syncing to Chain
+
+ ) }
+
+
+ )
+ }
+}
+
+export default withRouter(connect(
+ state => ({
+ serverRunning: store.getServerRunning(state),
+ isSynced: store.getSyncedToChain(state),
+ pubkey: store.getAccountPubkey(state),
+ currency: store.getCurrency(state),
+ balances: store.getAccountBalances(state),
+ }), {
+ fetchAccount: accountActions.fetchAccount,
+ fetchBalances: accountActions.fetchBalances,
+ },
+)(Sidebar))
diff --git a/packages/lightning-core/common/Streams.js b/packages/lightning-core/common/Streams.js
new file mode 100644
index 000000000..083c53d1d
--- /dev/null
+++ b/packages/lightning-core/common/Streams.js
@@ -0,0 +1,67 @@
+/* eslint-disable no-console */
+import React from 'react'
+import _ from 'lodash'
+import { connect } from 'react-redux'
+import { actions as notificationActions } from 'lightning-notifications'
+import { actions as accountsActions } from '../accounts'
+import { actions as transactionsActions } from '../transactions'
+import { store } from 'lightning-store'
+
+export class Streams extends React.Component {
+ componentWillReceiveProps(nextProps) {
+ if (this.props.serverRunning === false && nextProps.serverRunning === true) {
+ this.props.onFetchAccount()
+ this.props.onFetchChannels()
+ this.props.onFetchBalances()
+
+ this.interval = setInterval(() => {
+ // POLL
+ this.props.onFetchAccount()
+ this.props.onFetchChannels()
+ this.props.onFetchBalances()
+ }, 20000)
+
+ const fetchBalance = _.debounce(this.props.onFetchBalances, 2000)
+
+ const transactions = this.props.onSubscribeTransactions()
+ transactions.on('data', (data) => {
+ this.props.onFetchTransactions()
+ this.props.onFetchChannels()
+ this.props.onFetchAccount()
+ this.props.onSuccess(`Transaction ${ data.num_confirmations === 0 ? 'Received' : 'Completed' }`)
+ fetchBalance()
+ })
+
+ const invoices = this.props.onSubscribeInvoices()
+ invoices.on('data', () => {
+ this.props.onFetchTransactions()
+ this.props.onFetchChannels()
+ this.props.onFetchAccount()
+ this.props.onSuccess('Invoice Completed')
+ fetchBalance()
+ })
+ }
+ }
+
+ componentWillUnmount() {
+ window.clearInterval(this.interval)
+ }
+
+ render() {
+ return null
+ }
+}
+
+export default connect(
+ state => ({
+ serverRunning: store.getServerRunning(state),
+ }), {
+ onFetchAccount: accountsActions.fetchAccount,
+ onFetchBalances: accountsActions.fetchBalances,
+ onFetchChannels: accountsActions.fetchChannels,
+ onSubscribeTransactions: transactionsActions.subscribeTransactions,
+ onSubscribeInvoices: transactionsActions.subscribeInvoices,
+ onFetchTransactions: transactionsActions.fetchTransactions,
+ onSuccess: notificationActions.addNotification,
+ },
+)(Streams)
diff --git a/packages/lightning-core/common/index.js b/packages/lightning-core/common/index.js
new file mode 100644
index 000000000..454a6e64d
--- /dev/null
+++ b/packages/lightning-core/common/index.js
@@ -0,0 +1,8 @@
+export * from './CurrencyInput'
+export * from './Head'
+export * from './InfiniteScroll'
+export * from './Input'
+export * from './LoadingIcon'
+export * from './Money'
+export * from './Page'
+export * from './Prompt'
diff --git a/packages/lightning-core/components/Channels.js b/packages/lightning-core/components/Channels.js
deleted file mode 100644
index 9627b0206..000000000
--- a/packages/lightning-core/components/Channels.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react'
-
-import { Box, LinkWithIcon } from 'lightning-components'
-import { Link } from 'react-router'
-import { Header } from './common'
-import ChannelsList from './channels/ChannelsList'
-
-export const Channels = ({ channels, user, currency, sendLightning }) => {
- return (
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default Channels
diff --git a/packages/lightning-core/components/ChannelsCreate.js b/packages/lightning-core/components/ChannelsCreate.js
deleted file mode 100644
index d2b8cb074..000000000
--- a/packages/lightning-core/components/ChannelsCreate.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import React from 'react'
-
-import { Box, Text, LiftedInput } from 'lightning-components'
-import { Link } from 'react-router'
-import { Header, LiftedCurrencyInput } from './common'
-
-export const ChannelsCreate = ({ fillCreateForm, host, amount, createChannel,
- navigateToChannels, currency, isSynced, onError }) => {
- const handleHostChange = e => fillCreateForm({ host: e.target.value, amount })
- const handleAmountChange = e => fillCreateForm({ host, amount: e.target.value })
- const handleCreate = () => (isSynced ? createChannel({ host, amount }) :
- onError('Wait Until Synced to Create a Channel'))
-
- return (
-
-
-
-
-
-
-
-
-
- Create
-
-
-
- Cancel
-
-
-
-
-
- )
-}
-
-export default ChannelsCreate
diff --git a/packages/lightning-core/components/Payment.js b/packages/lightning-core/components/Payment.js
deleted file mode 100644
index b7f510ed8..000000000
--- a/packages/lightning-core/components/Payment.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react'
-
-import { Redirect, Match } from 'react-router'
-import { Box } from 'lightning-components'
-import PaymentRequestTabs from './payment/PaymentRequestTabs'
-
-import PaymentLightningContainer from '../containers/PaymentLightningContainer'
-import PaymentBitcoinContainer from '../containers/PaymentBitcoinContainer'
-
-export const Payment = () => {
- return (
-
-
-
-
-
-
-
- )
-}
-
-export default Payment
diff --git a/packages/lightning-core/components/PaymentBitcoin.js b/packages/lightning-core/components/PaymentBitcoin.js
deleted file mode 100644
index f10e01539..000000000
--- a/packages/lightning-core/components/PaymentBitcoin.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/* eslint-disable react/jsx-no-bind */
-
-import React from 'react'
-
-import { Box, Input, LiftedInput, LinkWithIcon, Text } from 'lightning-components'
-import { LiftedCurrencyInput } from './common'
-
-export const PaymentBitcoin = ({ form, changeBitcoinForm, sendCoins,
- address, currency, isSynced, onError }) => {
- const canSend = form.to && form.amount > 0
- const handleChange = (key, e) => changeBitcoinForm({ [key]: e.target.value })
- const emptyGuard = () => (canSend ? sendCoins(form) : onError('Input Payment Address and Amount'))
- const handleSend = () => (isSynced ? (
- emptyGuard()
- ) :
- onError('Wait Until Synced to Send Bitcoin')
- )
-
- return (
-
-
-
-
-
-
-
-
-
-
-
- Recieve Bitcoin:
-
-
-
-
- )
-}
-
-export default PaymentBitcoin
diff --git a/packages/lightning-core/components/PaymentLightning.js b/packages/lightning-core/components/PaymentLightning.js
deleted file mode 100644
index 880bf1f93..000000000
--- a/packages/lightning-core/components/PaymentLightning.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/* eslint-disable react/jsx-no-bind */
-
-import React from 'react'
-
-import { Box, LiftedInput, LinkWithIcon } from 'lightning-components'
-import { LiftedCurrencyInput } from './common'
-import PaymentLightningSend from './payment/PaymentLightningSend.js'
-
-export const PaymentLightning = ({ form, changeLightningForm, requestLightning,
- sendURI, changeSendURI, currency, account, sendLightningForm, sendLightning,
- isSynced, onError }) => {
- const handleChange = (key, e) => changeLightningForm({ [key]: e.target.value })
- const handleRequest = () => (form.amount > 0 ?
- requestLightning(form, account.pubKey) :
- onError('Input Request Amount')
- )
-
-
- const handleSend = () => (isSynced ? sendLightning(
- sendLightningForm.pubkey,
- sendLightningForm.amount,
- sendLightningForm.rHash,
- ) : (
- onError('Wait Until Synced to Send Lightning')
- ))
-
- return (
-
-
-
-
-
- 0 ? 'teal' : 'light-gray' }
- paddingBottom="none"
- />
- { form.uri ? (
-
-
-
-
- ) : null }
-
-
-
- )
-}
-
-export default PaymentLightning
diff --git a/packages/lightning-core/components/Settings.js b/packages/lightning-core/components/Settings.js
deleted file mode 100644
index c30363f03..000000000
--- a/packages/lightning-core/components/Settings.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-import _ from 'lodash'
-
-import { Box, Text } from 'lightning-components'
-
-export const Settings = ({ logs, account }) => {
- const styles = reactCSS({
- 'default': {
- page: {
- boxSizing: 'border-box',
- padding: 'large',
- direction: 'column',
- minWidth: 0,
- flex: 1,
- },
- title: {
- size: 'medium',
- paddingBottom: 'medium',
- color: 'gray',
- },
- account: {
- paddingBottom: 'large',
- },
- logs: {
- flex: 1,
- padding: 'medium',
- overflowX: 'auto',
- WebkitAppRegion: 'no-drag',
- zDepth: 1,
- width: '100%',
- boxSizing: 'border-box',
- },
- log: {
- size: 'small',
- color: 'gray',
- fontFamily: 'monospace',
- },
- },
- })
-
- return (
-
- { account.pubKey ? (
-
- PubKey: { account.pubKey }
-
- Lightning ID: { account.lnid }
-
- ) : null }
-
- Logs
-
- { _.map(logs, (log, i) => {
- return (
-
- { log }
-
- )
- }) }
-
- {/* Splash */}
-
- )
-}
-
-export default Settings
diff --git a/packages/lightning-core/components/Sidebar.js b/packages/lightning-core/components/Sidebar.js
deleted file mode 100644
index 17f25930b..000000000
--- a/packages/lightning-core/components/Sidebar.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-
-import { Box, Text } from 'lightning-components'
-import NavLinks from './nav/NavLinks'
-import NavFooter from './nav/NavFooter'
-
-export const Sidebar = ({ navigateToSubpage, user, currency, account,
- activeTab, isSynced }) => {
- const styles = reactCSS({
- 'default': {
- sidebar: {
- direction: 'column',
- spread: true,
- flex: 1,
- },
- section: {
- padding: 'small',
- },
- synced: {
- background: 'teal',
- direction: 'column',
- align: 'center',
- verticalAlign: 'center',
- marginLeft: -7,
- marginTop: 7,
- marginRight: -7,
- marginBottom: -7,
- borderBottomLeftRadius: 4,
- height: 34,
- },
- syncedText: {
- color: 'black',
- size: 'small',
- },
- },
- })
-
- return (
-
-
-
-
-
-
- { isSynced ? null : (
-
- Syncing to Chain
-
- ) }
-
-
- )
-}
-
-export default Sidebar
diff --git a/packages/lightning-core/components/Splash.js b/packages/lightning-core/components/Splash.js
deleted file mode 100644
index 0e0f6626c..000000000
--- a/packages/lightning-core/components/Splash.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import React from 'react'
-
-import { Box, colors } from 'lightning-components'
-
-export const Channels = ({ navigateToHome }) => {
- return (
-
-
-
-
-
- Create a New Wallet
-
-
- Connect Wallet
-
-
-
- )
-}
-
-export default Channels
diff --git a/packages/lightning-core/components/Transactions.js b/packages/lightning-core/components/Transactions.js
deleted file mode 100644
index 84421c04c..000000000
--- a/packages/lightning-core/components/Transactions.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react'
-
-import TransactionsNavBar from './transactions/TransactionsNavBar'
-import TransactionsListContainer from '../containers/TransactionsListContainer'
-import { Header } from './common'
-
-
-export const Transactions = ({ params }) => {
- return (
-
-
-
-
-
- )
-}
-
-export default Transactions
diff --git a/packages/lightning-core/components/Wallet.js b/packages/lightning-core/components/Wallet.js
deleted file mode 100644
index 39375d602..000000000
--- a/packages/lightning-core/components/Wallet.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react'
-
-import { Box } from 'lightning-components'
-import WalletsList from './wallet/WalletsList'
-import { Header, CurrencyChanger } from './common'
-
-export const Wallet = ({ currency, changeCurrency, activeWallet, wallets,
- switchWallet, account }) => {
- const changer = (
-
- )
- return (
-
-
-
-
-
-
-
- )
-}
-
-export default Wallet
diff --git a/packages/lightning-core/components/channels/ChannelAllocation.js b/packages/lightning-core/components/channels/ChannelAllocation.js
deleted file mode 100644
index 23f367cea..000000000
--- a/packages/lightning-core/components/channels/ChannelAllocation.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react'
-
-import { Box } from 'lightning-components'
-import ChannelAllocationBar from './ChannelAllocationBar'
-
-export const ChannelAllocation = ({ left, right, status }) => {
- const total = left + right
-
- return (
-
-
-
-
- )
-}
-
-export default ChannelAllocation
diff --git a/packages/lightning-core/components/channels/ChannelAllocationBar.js b/packages/lightning-core/components/channels/ChannelAllocationBar.js
deleted file mode 100644
index aa7b9d507..000000000
--- a/packages/lightning-core/components/channels/ChannelAllocationBar.js
+++ /dev/null
@@ -1,72 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-
-import { Box, Text } from 'lightning-components'
-
-export const ChannelAllocationBar = ({ percentage, status, align }) => {
- const styles = reactCSS({
- 'default': {
- wrap: {
- flex: 1,
- direction: 'row',
- },
- bar: {
- boxShadow: 'inset 0 -2px rgba(0,0,0,.1)',
- marginRight: 1,
- marginLeft: 1,
- display: 'flex',
- },
- percentage: {
- opacity: 0.5,
- size: 'large',
- padding: 'small',
- color: 'black',
- },
- },
- 'align-left': {
- wrap: {
- align: 'right',
- },
- bar: {
- background: 'teal',
- borderRadius: '2px 0 0 2px',
- width: `${ percentage }%`,
- },
- },
- 'align-right': {
- wrap: {
- align: 'left',
- },
- bar: {
- background: 'dark-teal',
- borderRadius: '0 2px 2px 0',
- width: `${ percentage }%`,
- },
- },
- 'hide-percentage': {
- percentage: {
- display: 'none',
- },
- },
- 'status-pending': {
- bar: {
- background: 'lighter-gray',
- },
- },
- }, {
- 'hide-percentage': percentage < 50,
- 'status-pending': status === 'pending',
- 'align-left': align === 'left',
- 'align-right': align === 'right',
- })
-
- return (
-
-
- { Math.floor(percentage) }%
-
-
- )
-}
-
-export default ChannelAllocationBar
diff --git a/packages/lightning-core/components/channels/ChannelsList.js b/packages/lightning-core/components/channels/ChannelsList.js
deleted file mode 100644
index d2a9e0ebd..000000000
--- a/packages/lightning-core/components/channels/ChannelsList.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-import _ from 'lodash'
-
-import { Box, Icon, Text } from 'lightning-components'
-import ChannelsListItem from './ChannelsListItem'
-
-export const ChannelsList = ({ channels, currency, user, sendLightning }) => {
- const styles = reactCSS({
- 'default': {
- channels: {
- borderTop: '1px solid #eee',
- },
- channel: {
- borderBottom: '1px solid #eee',
- },
- noChannels: {
- borderBottom: '1px solid #eee',
- padding: 'medium',
- direction: 'row',
- verticalAlign: 'center',
- },
- },
- })
-
- return (
-
- { _.map(channels, (channel, i) => {
- return (
-
-
-
- )
- }) }
- { channels.length === 0 ? (
-
-
-
- No Channels Yet
- Create a Channel Below
-
-
- ) : null }
-
- )
-}
-
-export default ChannelsList
diff --git a/packages/lightning-core/components/channels/ChannelsListItem.js b/packages/lightning-core/components/channels/ChannelsListItem.js
deleted file mode 100644
index b2a949a1c..000000000
--- a/packages/lightning-core/components/channels/ChannelsListItem.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-
-import { Box, Text } from 'lightning-components'
-import { Money, Identity } from '../common'
-import ChannelAllocation from './ChannelAllocation'
-
-export const ChannelsListItem = ({ localAllocation, remoteAllocation, user,
- status, currency, remotePubKey, sendLightning }) => {
- const styles = reactCSS({
- 'default': {
- item: {
- direction: 'row',
- padding: 'small',
- verticalAlign: 'center',
- },
- left: {
- flex: 1,
- paddingLeft: 'small',
- },
- center: {
- flex: 3,
- height: 54,
- direction: 'row',
- },
- right: {
- flex: 2,
- textAlign: 'right',
- overflow: 'hidden',
- paddingRight: 'small',
- },
-
- headText: {
- fontSize: 'medium',
- color: 'black',
- display: 'block',
- overflow: 'hidden',
- },
- subText: {
- fontSize: 'small',
- display: 'block',
- color: 'gray',
- },
- },
- })
-
- const handleQuickPay = () => sendLightning(remotePubKey, 1000)
-
- return (
-
-
-
-
-
-
- { status === 'pending' ? (
- '(pending)'
- ) : (
-
- ) }
-
-
-
-
-
-
-
-
-
-
-
-
- PAY ·
-
-
-
- )
-}
-
-export default ChannelsListItem
diff --git a/packages/lightning-core/components/common/CurrencyChanger.js b/packages/lightning-core/components/common/CurrencyChanger.js
deleted file mode 100644
index 1de489c28..000000000
--- a/packages/lightning-core/components/common/CurrencyChanger.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react'
-import _ from 'lodash'
-
-import { Select } from 'lightning-components'
-import { currencies } from '../../helpers'
-
-export const CurrencyChanger = ({ currency, onChange }) => {
- const all = _.map(currencies.all, (label, value) => ({ value, label }))
- const handleChange = e => onChange(e.target.value)
-
- return (
-
- )
-}
-
-export default CurrencyChanger
diff --git a/packages/lightning-core/components/common/Header.js b/packages/lightning-core/components/common/Header.js
deleted file mode 100644
index 5357e2e15..000000000
--- a/packages/lightning-core/components/common/Header.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-
-import { Box, Text } from 'lightning-components'
-
-export const Header = ({ background, color, center, title, right }) => {
- const styles = reactCSS({
- 'default': {
- header: {
- background,
- color,
- direction: 'row',
- spread: true,
- padding: 'large',
- paddingBottom: 'small',
- paddingTop: 'xl',
- flexShrink: 0,
- },
- },
- 'center': {
- },
- }, { center })
-
- return (
-
-
- { title }
- { right }
-
- )
-}
-
-Header.defaultProps = {
- color: 'light-gray',
-}
-
-export default Header
diff --git a/packages/lightning-core/components/common/Identity.js b/packages/lightning-core/components/common/Identity.js
deleted file mode 100644
index f02c23e78..000000000
--- a/packages/lightning-core/components/common/Identity.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react'
-
-import { Text } from 'lightning-components'
-
-export const Identity = ({ name, user, maxWidth }) => {
- return (
-
- { name === user ? 'You' : name }
-
- )
-}
-
-export default Identity
diff --git a/packages/lightning-core/components/common/LiftedCurrencyInput.js b/packages/lightning-core/components/common/LiftedCurrencyInput.js
deleted file mode 100644
index 3284a2417..000000000
--- a/packages/lightning-core/components/common/LiftedCurrencyInput.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react'
-
-import { LiftedInput } from 'lightning-components'
-import currencies, { removeCommas } from '../../helpers/currencies'
-
-export const LiftedCurrencyInput = (props) => {
- const currency = currencies.find(props.currency)
- const handleChange = (e) => {
- props.onChange && props.onChange({ target: { value: removeCommas(e.target.value) } })
- }
- return (
-
- )
-}
-
-export default LiftedCurrencyInput
diff --git a/packages/lightning-core/components/common/Money.js b/packages/lightning-core/components/common/Money.js
deleted file mode 100644
index cbcb5ad5e..000000000
--- a/packages/lightning-core/components/common/Money.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react'
-
-import { currencies } from '../../helpers'
-
-export const Money = ({ currency, amount, sign }) => {
- const money = currencies.find(currency)
-
- return (
-
- { sign ? `${ money.sign } ` : null }
- { money.format(amount) }
-
- )
-}
-
-export default Money
diff --git a/packages/lightning-core/components/common/MoneyCode.js b/packages/lightning-core/components/common/MoneyCode.js
deleted file mode 100644
index a9d907082..000000000
--- a/packages/lightning-core/components/common/MoneyCode.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-
-import { currencies } from '../../helpers'
-
-export const MoneyCode = ({ currency }) => {
- const money = currencies.find(currency)
-
- return { money.code }
-}
-
-export default MoneyCode
diff --git a/packages/lightning-core/components/common/MoneySign.js b/packages/lightning-core/components/common/MoneySign.js
deleted file mode 100644
index 18c58ea94..000000000
--- a/packages/lightning-core/components/common/MoneySign.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-
-import { currencies } from '../../helpers'
-
-export const MoneySign = ({ currency }) => {
- const money = currencies.find(currency)
-
- return { money.sign }
-}
-
-export default MoneySign
diff --git a/packages/lightning-core/components/common/index.js b/packages/lightning-core/components/common/index.js
deleted file mode 100644
index 3e918e81f..000000000
--- a/packages/lightning-core/components/common/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export { default as CurrencyChanger } from './CurrencyChanger'
-export { default as Identity } from './Identity'
-export { default as LiftedCurrencyInput } from './LiftedCurrencyInput'
-export { default as Money } from './Money'
-export { default as MoneyCode } from './MoneyCode'
-export { default as MoneySign } from './MoneySign'
-export { default as Header } from './Header'
diff --git a/packages/lightning-core/components/common/story.js b/packages/lightning-core/components/common/story.js
deleted file mode 100644
index e2afb2202..000000000
--- a/packages/lightning-core/components/common/story.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react'
-import { storiesOf } from '@kadira/storybook'
-
-import CurrencyChanger from './CurrencyChanger'
-import Identity from './Identity'
-import Money from './Money'
-import MoneySign from './MoneySign'
-
-storiesOf('CurrencyChanger', module)
- .add('changer', () => (
-
- ))
-
-storiesOf('Identity', module)
- .add('identity', () => (
-
- ))
- .add('identity same name and user', () => (
-
- ))
-
-storiesOf('Money', module)
- .add('money', () => (
-
- ))
- .add('money with sign', () => (
-
- ))
- .add('usd', () => (
-
- ))
- .add('usd with sign', () => (
-
- ))
-
-storiesOf('MoneySign', module)
- .add('btc sign', () => (
-
- ))
- .add('usd sign', () => (
-
- ))
diff --git a/packages/lightning-core/components/nav/story.js b/packages/lightning-core/components/nav/story.js
deleted file mode 100644
index d4a7c8d46..000000000
--- a/packages/lightning-core/components/nav/story.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react'
-import { storiesOf } from '@kadira/storybook'
-
-import NavLinks from './NavLinks'
-import NavFooter from './NavFooter'
-
-const user = {
- identity: 'case@casesandberg.com',
- amount: '5.3021',
- denomination: 'BTC',
-}
-
-storiesOf('NavLinks', module)
- .add('send money `active`', () => (
-
- ))
- .add('transactions `active`', () => (
-
- ))
-
-storiesOf('NavFooter', module)
- .add('`case@casesandberg.com` `8.5412`', () => (
-
- ))
diff --git a/packages/lightning-core/components/payment/PaymentLightningSend.js b/packages/lightning-core/components/payment/PaymentLightningSend.js
deleted file mode 100644
index 799832988..000000000
--- a/packages/lightning-core/components/payment/PaymentLightningSend.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import React from 'react'
-
-import { Box, LiftedInput, Text } from 'lightning-components'
-import { LiftedCurrencyInput } from '../common'
-
-export const PaymentLIghtningSend = ({ sendURI, onChange, onSend, currency, form,
- isSynced }) => {
- const handleSendURI = e => onChange(e.target.value)
- const handleSend = () => onSend(sendURI)
- const trayOpen = form.amount && form.pubkey
-
- return (
-
- { trayOpen ? null : (
- Send:
- ) }
-
-
- { trayOpen ? (
-
-
-
-
-
- Send
-
- ) : null }
-
-
- )
-}
-
-export default PaymentLIghtningSend
diff --git a/packages/lightning-core/components/payment/PaymentRequestTabs.js b/packages/lightning-core/components/payment/PaymentRequestTabs.js
deleted file mode 100644
index 8d30de62f..000000000
--- a/packages/lightning-core/components/payment/PaymentRequestTabs.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-
-import { Box, Tabs, colors } from 'lightning-components'
-
-export const PaymentRequestTabs = ({ selected, onTabChange }) => {
- const styles = reactCSS({
- 'default': {
- bar: {
- background: 'lightest-gray',
- height: 48,
- },
- tabs: {
- color: colors.black,
- inactive: colors.black,
- },
- },
- })
-
- const tabs = [
- {
- label: 'Lightning',
- value: 'lightning',
- href: '/payment/lightning',
- },
- {
- label: 'Bitcoin',
- value: 'bitcoin',
- href: '/payment/bitcoin',
- },
- ]
-
- return (
-
-
-
- )
-}
-
-export default PaymentRequestTabs
diff --git a/packages/lightning-core/components/transactions/TransactionsList.js b/packages/lightning-core/components/transactions/TransactionsList.js
deleted file mode 100644
index 5863fe932..000000000
--- a/packages/lightning-core/components/transactions/TransactionsList.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-import _ from 'lodash'
-
-import { Box, Text, Icon } from 'lightning-components'
-import TransactionsListItem from './TransactionsListItem'
-
-export const TransactionList = ({ transactions, user, currency, sort }) => {
- const styles = reactCSS({
- 'default': {
- transaction: {
- borderBottom: '1px solid #eee',
- },
- },
- })
-
- const idToLabel = id => ({
- 'recent': 'Recent',
- 'in-progress': 'In Progress',
- 'complete': 'Complete',
- }[id])
-
- return (
-
- { _.map(transactions, (transaction, i) => {
- return (
-
-
-
- )
- }) }
- { transactions.length === 0 ? (
-
-
-
-
- { `No ${ idToLabel(sort) } Transactions` }
-
-
- ) : null }
-
- )
-}
-
-export default TransactionList
diff --git a/packages/lightning-core/components/transactions/TransactionsListItem.js b/packages/lightning-core/components/transactions/TransactionsListItem.js
deleted file mode 100644
index 654c869fa..000000000
--- a/packages/lightning-core/components/transactions/TransactionsListItem.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-
-import { Box, Text } from 'lightning-components'
-import { Identity, Money } from '../common'
-
-export const TranscationListItem = ({ from, user, to, description, amount,
- currency, status }) => {
- const styles = reactCSS({
- 'default': {
- row: {
- direction: 'row',
- padding: 'medium',
- spread: true,
- background: 'white',
- },
- left: {
- direction: 'column',
- verticalAlign: 'center',
- minWidth: 0,
- size: 'medium',
- },
- right: {
- direction: 'column',
- verticalAlign: 'center',
- align: 'right',
- minWidth: 150,
- paddingLeft: 'medium',
- },
- focusText: {
- color: 'black',
- size: 'medium',
- },
- descText: {
- size: 'small',
- color: 'light-gray',
- paddingTop: 'xs',
- },
- },
- })
-
- return (
-
-
-
-
- paid
-
-
- { description ? (
- { description }
- ) : null }
-
-
-
-
-
- { status }
-
-
- )
-}
-
-export default TranscationListItem
diff --git a/packages/lightning-core/components/transactions/TransactionsNavBar.js b/packages/lightning-core/components/transactions/TransactionsNavBar.js
deleted file mode 100644
index 9f87d2bb4..000000000
--- a/packages/lightning-core/components/transactions/TransactionsNavBar.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-
-import { Box, Tabs, colors } from 'lightning-components'
-
-export const TranscationNavBar = ({ selected, onTabChange }) => {
- const styles = reactCSS({
- 'default': {
- bar: {
- background: 'teal',
- direction: 'row',
- spread: true,
- flexShrink: 0,
- },
- tabs: {
- color: colors.white,
- inactive: colors.black,
- },
- search: {
- color: colors.black,
- opacity: 0.47,
- paddingRight: 'medium',
- display: 'flex',
- verticalAlign: 'center',
- },
- },
- 'selected-search': {
- search: {
- color: colors.white,
- opacity: 0.87,
- },
- },
- }, { 'selected-search': selected === 'search' })
-
- const tabs = [
- {
- label: 'Recent',
- value: 'recent',
- href: '/transactions/recent',
- },
- {
- label: 'In Progress',
- value: 'in-progress',
- href: '/transactions/in-progress',
- },
- {
- label: 'Complete',
- value: 'complete',
- href: '/transactions/complete',
- },
- ]
-
- return (
-
-
- { /*
-
- */ }
-
- )
-}
-
-export default TranscationNavBar
diff --git a/packages/lightning-core/components/transactions/story.js b/packages/lightning-core/components/transactions/story.js
deleted file mode 100644
index 93ae9f206..000000000
--- a/packages/lightning-core/components/transactions/story.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import React from 'react'
-import { storiesOf } from '@kadira/storybook'
-
-import TransactionsList from './TransactionsList'
-import TransactionsListItem from './TransactionsListItem'
-import TransactionsNavBar from './TransactionsNavBar'
-
-const transaction = {
- id: '0',
- from: 'case@casesandberg.com',
- to: 'joseph@lightning.network',
- amount: 0.0021,
- status: 'complete',
- description: 'For a really cool book',
-}
-
-const transaction2 = {
- id: '1',
- from: 'stark@lightning.network',
- to: 'case@casesandberg.com',
- amount: 1.4439,
- status: 'complete',
-}
-
-const transcationNoDesc = Object.assign({}, transaction, { description: '' })
-
-const user = {
- identity: 'case@casesandberg.com',
-}
-
-const currency = 'btc'
-
-storiesOf('TransactionsList', module)
- .add('transactions', () => (
-
- ))
-
-storiesOf('TransactionsListItem', module)
- .add('transcation', () => (
-
- ))
- .add('transcation2', () => (
-
- ))
- .add('transcation without description', () => (
-
- ))
-
-storiesOf('TransactionsNavBar', module)
- .add('`recent` selected', () => (
-
- ))
- .add('`in-progress` selected', () => (
-
- ))
- .add('`complete` selected', () => (
-
- ))
- .add('`search` selected', () => (
-
- ))
diff --git a/packages/lightning-core/components/wallet/WalletsList.js b/packages/lightning-core/components/wallet/WalletsList.js
deleted file mode 100644
index 53e064ca3..000000000
--- a/packages/lightning-core/components/wallet/WalletsList.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-import _ from 'lodash'
-
-import WalletsListItem from './WalletsListItem'
-
-export const WalletsList = ({ wallets, activeWallet, currency, onWalletChange,
- account }) => {
- const styles = reactCSS({
- 'default': {
- wallets: {
- borderTop: '1px solid #eee',
- },
- wallet: {
- borderBottom: '1px solid #eee',
- },
- },
- })
-
- return (
-
- { _.map(wallets, (wallet, i) => {
- return (
-
-
-
- )
- }) }
-
- )
-}
-
-export default WalletsList
diff --git a/packages/lightning-core/components/wallet/WalletsListCompact.js b/packages/lightning-core/components/wallet/WalletsListCompact.js
deleted file mode 100644
index 1cf11dc55..000000000
--- a/packages/lightning-core/components/wallet/WalletsListCompact.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react'
-import _ from 'lodash'
-
-import WalletsListCompactItem from './WalletsListCompactItem'
-
-export const WalletsListCompact = ({ wallets, currency, onSelect, selectedWallet }) => {
- return (
-
- { _.map(wallets, (wallet, i) => {
- return (
-
- )
- }) }
-
- )
-}
-
-export default WalletsListCompact
diff --git a/packages/lightning-core/components/wallet/WalletsListCompactItem.js b/packages/lightning-core/components/wallet/WalletsListCompactItem.js
deleted file mode 100644
index b0c541097..000000000
--- a/packages/lightning-core/components/wallet/WalletsListCompactItem.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import React from 'react'
-import reactCSS, { hover as h } from 'reactcss'
-
-import { Box, Icon, Media, Text } from 'lightning-components'
-import { Money } from '../common'
-
-import { total } from '../../helpers/wallet'
-
-export const WalletsListCompactItem = ({ active, onSelect, hover, amount, id,
- identity, currency }) => {
- const styles = reactCSS({
- 'default': {
- item: {
- cursor: 'pointer',
- display: 'block',
- marginBottom: 1,
- zDepth: 1,
- padding: 'medium',
- },
-
- radio: {
- name: 'radiobox-blank',
- color: 'light-gray',
- },
- },
- 'active': {
- wrap: {
- block: true,
- },
- switch: {
- display: 'none',
- },
-
- radio: {
- name: 'radiobox-marked',
- color: 'teal',
- },
- },
- 'active-false': {
- total: {
- 'black': false,
- 'light-gray': true,
- },
- identity: {
- 'light-gray': true,
- },
- },
- 'hover': {
- switch: {
- display: 'flex',
- },
- },
- }, { active, hover, 'active-false': active === false })
-
- const handleClick = () => onSelect(id)
-
- return (
-
-
- ) : (
-
- ) }
- >
- { identity }
-
-
-
-
-
- )
-}
-
-WalletsListCompactItem.defaultProps = {
- active: false,
-}
-
-export default h(WalletsListCompactItem)
diff --git a/packages/lightning-core/components/wallet/WalletsListItem.js b/packages/lightning-core/components/wallet/WalletsListItem.js
deleted file mode 100644
index 8eff31ba3..000000000
--- a/packages/lightning-core/components/wallet/WalletsListItem.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import React from 'react'
-import reactCSS, { hover as h } from 'reactcss'
-
-import { Box, Text } from 'lightning-components'
-import { Money } from '../common'
-import WalletsListItemDetail from './WalletsListItemDetail'
-
-import { total } from '../../helpers/wallet'
-
-export const WalletsListItem = ({ active, hover, amount, currency, identity,
- account }) => {
- const styles = reactCSS({
- 'default': {
- item: {
- zDepth: active ? 1 : 0,
- padding: 'large',
- paddingRight: 'medium',
- direction: 'row',
- spread: true,
- position: 'relative',
- },
-
- left: {
- direction: 'column',
- verticalAlign: 'center',
- fontSize: 'medium',
- color: 'gray',
- maxWidth: 300,
- },
- total: {
- size: 'xl',
- color: 'black',
- },
-
- right: {
- direction: 'column',
- align: 'right',
- },
- switch: {
- position: 'absolute',
- top: 0,
- right: 0,
- bottom: 0,
- left: 0,
- alignItems: 'center',
- justifyContent: 'center',
- cursor: 'pointer',
- display: 'none',
- },
- },
- 'active': {
- switch: {
- display: 'none',
- },
- },
- 'active-false': {
- total: {
- 'black': false,
- 'light-gray': true,
- },
- identity: {
- 'light-gray': true,
- },
- },
- 'hover': {
- switch: {
- display: 'flex',
- },
- },
- }, { hover, active, 'active-false': active === false })
-
- return (
-
-
-
-
-
-
- { identity || account.pubKey }
-
-
-
-
-
-
-
-
-
- )
-}
-
-WalletsListItem.defaultProps = {
- active: false,
-}
-
-export default h(WalletsListItem)
diff --git a/packages/lightning-core/components/wallet/WalletsListItemDetail.js b/packages/lightning-core/components/wallet/WalletsListItemDetail.js
deleted file mode 100644
index 7a9d8bf0f..000000000
--- a/packages/lightning-core/components/wallet/WalletsListItemDetail.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react'
-import reactCSS from 'reactcss'
-
-import { Box, Text } from 'lightning-components'
-import { Money } from '../common'
-
-export const WalletsListItemDetail = ({ active, amount, currency, label }) => {
- const styles = reactCSS({
- 'default': {
- detail: {
- direction: 'row',
- align: 'right',
- fontSize: 'medium',
- color: 'gray',
- },
- label: {
- width: 80,
- paddingLeft: 'medium',
- },
- },
- 'active-false': {
- labelText: {
- 'light-gray': true,
- },
- },
- }, { 'active-false': active === false })
-
- return (
-
-
-
-
-
- { label }
-
-
- )
-}
-
-export default WalletsListItemDetail
diff --git a/packages/lightning-core/components/wallet/story.js b/packages/lightning-core/components/wallet/story.js
deleted file mode 100644
index 350b0f530..000000000
--- a/packages/lightning-core/components/wallet/story.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import React from 'react'
-import { storiesOf } from '@kadira/storybook'
-
-import WalletsList from './WalletsList'
-import WalletsListItem from './WalletsListItem'
-
-const wallets = [
- {
- id: 0,
- identity: 'case@casesandberg.com',
- amount: {
- total: 8.541222,
- blockchain: 1.51102,
- channels: 7.030202,
- },
- }, {
- id: 1,
- identity: 'safe@casesandberg.com',
- amount: {
- total: 324.1000345,
- blockchain: 324.1000345,
- channels: 0,
- },
- },
-]
-
-const currency = 'btc'
-
-storiesOf('WalletsList', module)
- .add('wallets active: 0', () => (
-
- ))
- .add('wallets active: 1', () => (
-
- ))
-
-storiesOf('WalletsListItem', module)
- .add('wallet', () => (
-
- ))
- .add('wallet `active`', () => (
-
- ))
diff --git a/packages/lightning-core/containers/ChannelsContainer.js b/packages/lightning-core/containers/ChannelsContainer.js
deleted file mode 100644
index 6b1fb279d..000000000
--- a/packages/lightning-core/containers/ChannelsContainer.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { store } from 'lightning-store'
-import { actions as channelsActions } from '../reducers/channels'
-import { actions as paymentActions } from '../reducers/payment'
-
-import Channels from '../components/Channels'
-
-const mapStateToProps = state => ({
- user: store.getActiveWallet(state),
- channels: store.getChannels(state),
- currency: store.getCurrency(state),
-})
-
-class ChannelsContainer extends React.Component {
- componentDidMount() { this.props.getChannels() }
-
- render() {
- return (
-
- )
- }
-}
-
-export default connect(
- mapStateToProps,
- { ...channelsActions, ...paymentActions }
-)(ChannelsContainer)
diff --git a/packages/lightning-core/containers/ChannelsCreateContainer.js b/packages/lightning-core/containers/ChannelsCreateContainer.js
deleted file mode 100644
index 7139d444d..000000000
--- a/packages/lightning-core/containers/ChannelsCreateContainer.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { connect } from 'react-redux'
-import { store } from 'lightning-store'
-import { actions as notificationsActions } from 'lightning-notifications'
-import { actions as channelsActions } from '../reducers/channels'
-
-import ChannelsCreate from '../components/ChannelsCreate'
-
-const mapStateToProps = state => ({
- currency: store.getCurrency(state),
- isSynced: store.getSyncedToChain(state),
- ...store.getChannelsCreateForm(state),
-})
-
-const ChannelsCreateContainer = connect(
- mapStateToProps,
- { ...channelsActions, ...notificationsActions }
-)(ChannelsCreate)
-
-export default ChannelsCreateContainer
diff --git a/packages/lightning-core/containers/PaymentBitcoinContainer.js b/packages/lightning-core/containers/PaymentBitcoinContainer.js
deleted file mode 100644
index e8dd5af61..000000000
--- a/packages/lightning-core/containers/PaymentBitcoinContainer.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { store } from 'lightning-store'
-import { actions as notificationsActions } from 'lightning-notifications'
-import { actions as paymentActions } from '../reducers/payment'
-
-import PaymentBitcoin from '../components/PaymentBitcoin'
-
-const mapStateToProps = state => ({
- currency: store.getCurrency(state),
- form: store.getSendBitcoinForm(state),
- isSynced: store.getSyncedToChain(state),
- address: store.getBitcoinAddress(state),
-})
-
-class PaymentBitcoinContainer extends React.Component {
- componentDidMount() { this.props.newWitnessAddress() }
-
- render() {
- return (
-
- )
- }
-}
-
-export default connect(
- mapStateToProps,
- { ...paymentActions, ...notificationsActions }
-)(PaymentBitcoinContainer)
diff --git a/packages/lightning-core/containers/PaymentLightningContainer.js b/packages/lightning-core/containers/PaymentLightningContainer.js
deleted file mode 100644
index a01e6ce75..000000000
--- a/packages/lightning-core/containers/PaymentLightningContainer.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import { connect } from 'react-redux'
-import { store } from 'lightning-store'
-import { actions as notificationsActions } from 'lightning-notifications'
-import { actions as paymentActions } from '../reducers/payment'
-
-import PaymentLightning from '../components/PaymentLightning'
-
-const mapStateToProps = state => ({
- currency: store.getCurrency(state),
- form: store.getRequestLightningForm(state),
- account: store.getAccountInfo(state),
- sendURI: store.getSendLightningURI(state),
- sendLightningForm: store.getSendLightningForm(state),
- isSynced: store.getSyncedToChain(state),
-})
-
-const PaymentLightningContainer = connect(
- mapStateToProps,
- { ...paymentActions, ...notificationsActions }
-)(PaymentLightning)
-
-export default PaymentLightningContainer
diff --git a/packages/lightning-core/containers/SettingsContainer.js b/packages/lightning-core/containers/SettingsContainer.js
deleted file mode 100644
index 8d78cce06..000000000
--- a/packages/lightning-core/containers/SettingsContainer.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { connect } from 'react-redux'
-import { store } from 'lightning-store'
-
-import Settings from '../components/Settings'
-
-const mapStateToProps = state => ({
- logs: store.getRecentLogs(state),
- account: store.getAccountInfo(state),
-})
-
-const SettingsContainer = connect(
- mapStateToProps
-)(Settings)
-
-export default SettingsContainer
diff --git a/packages/lightning-core/containers/SidebarContainer.js b/packages/lightning-core/containers/SidebarContainer.js
deleted file mode 100644
index e1bc9ae63..000000000
--- a/packages/lightning-core/containers/SidebarContainer.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { store } from 'lightning-store'
-import { actions as uiActions } from '../reducers/ui'
-import { actions as walletsActions } from '../reducers/wallets'
-
-import Sidebar from '../components/Sidebar'
-
-const mapStateToProps = (state, { activePage }) => ({
- user: store.getActiveWallet(state),
- currency: store.getCurrency(state),
- account: store.getAccountInfo(state),
- isSynced: store.getSyncedToChain(state),
- activePage,
-})
-
-export class SidebarContainer extends React.Component {
- componentDidMount() {
- this.props.fetchAccount()
- this.props.activeTab !== 'wallets' && this.props.fetchBalances()
- }
-
- render() {
- return (
-
- )
- }
-}
-
-export default connect(
- mapStateToProps,
- { ...uiActions, ...walletsActions }
-)(SidebarContainer)
diff --git a/packages/lightning-core/containers/SplashContainer.js b/packages/lightning-core/containers/SplashContainer.js
deleted file mode 100644
index 6afead473..000000000
--- a/packages/lightning-core/containers/SplashContainer.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { connect } from 'react-redux'
-
-import Splash from '../components/Splash'
-
-const mapStateToProps = () => ({
-
-})
-
-const SplashContainer = connect(
- mapStateToProps
-)(Splash)
-
-export default SplashContainer
diff --git a/packages/lightning-core/containers/TransactionsContainer.js b/packages/lightning-core/containers/TransactionsContainer.js
deleted file mode 100644
index 5413413e8..000000000
--- a/packages/lightning-core/containers/TransactionsContainer.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { actions } from '../reducers/transactions'
-
-import Transactions from '../components/Transactions'
-
-const mapStateToProps = () => ({
-
-})
-
-class TransactionsContainer extends React.Component {
- componentDidMount() { this.props.getTransactions() }
-
- render() {
- return (
-
- )
- }
-}
-
-export default connect(
- mapStateToProps,
- actions
-)(TransactionsContainer)
diff --git a/packages/lightning-core/containers/TransactionsListContainer.js b/packages/lightning-core/containers/TransactionsListContainer.js
deleted file mode 100644
index 90a83769b..000000000
--- a/packages/lightning-core/containers/TransactionsListContainer.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { connect } from 'react-redux'
-import { store } from 'lightning-store'
-import { actions } from '../reducers/transactions'
-
-import TransactionsList from '../components/transactions/TransactionsList'
-
-const mapStateToProps = (state, props) => ({
- transactions: store.getRecentTransactionsByStatus(state, props.sort),
- user: store.getActiveWallet(state),
- currency: store.getCurrency(state),
-})
-
-const TransactionsListContainer = connect(
- mapStateToProps,
- actions
-)(TransactionsList)
-
-export default TransactionsListContainer
diff --git a/packages/lightning-core/containers/WalletContainer.js b/packages/lightning-core/containers/WalletContainer.js
deleted file mode 100644
index da74621ce..000000000
--- a/packages/lightning-core/containers/WalletContainer.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react'
-import { connect } from 'react-redux'
-import { store } from 'lightning-store'
-import { actions as uiActions } from '../reducers/ui'
-import { actions as walletsActions } from '../reducers/wallets'
-
-import Wallet from '../components/Wallet'
-
-const mapStateToProps = state => ({
- wallets: store.getWallets(state),
- currency: store.getCurrency(state),
- account: store.getAccountInfo(state),
- activeWallet: store.getActiveWalletIndex(state),
-})
-
-class WalletContainer extends React.Component {
- componentDidMount() { this.props.fetchBalances() }
-
- render() {
- return (
-
- )
- }
-}
-
-export default connect(
- mapStateToProps,
- { ...walletsActions, ...uiActions }
-)(WalletContainer)
diff --git a/packages/lightning-core/fixtures/channels.js b/packages/lightning-core/fixtures/channels.js
deleted file mode 100644
index eac7aeb49..000000000
--- a/packages/lightning-core/fixtures/channels.js
+++ /dev/null
@@ -1,48 +0,0 @@
-export default [
- {
- total: 2,
- parties: [
- {
- identity: 'case@casesandberg.com',
- allocation: 1.56,
- }, {
- identity: 'btc@wsj.com',
- allocation: 0.44,
- },
- ],
- }, {
- total: 4,
- parties: [
- {
- identity: 'case@casesandberg.com',
- allocation: 2.44,
- }, {
- identity: 'joseph@lightningnetwork.com',
- allocation: 1.56,
- },
- ],
- }, {
- total: 6,
- status: 'pending',
- parties: [
- {
- identity: 'case@casesandberg.com',
- allocation: 3,
- }, {
- identity: 'stark@lightningnetwork.com',
- allocation: 3,
- },
- ],
- }, {
- total: 6,
- parties: [
- {
- identity: 'case@casesandberg.com',
- allocation: 2,
- }, {
- identity: 'henrymb67@gmail.com',
- allocation: 4,
- },
- ],
- },
-]
diff --git a/packages/lightning-core/fixtures/logs.js b/packages/lightning-core/fixtures/logs.js
deleted file mode 100644
index cb93316ee..000000000
--- a/packages/lightning-core/fixtures/logs.js
+++ /dev/null
@@ -1,5 +0,0 @@
-export default [
- 'lnd: 12:51:03 2016-10-09 [INF] LTND: Version 0.1.0-alpha',
- 'lnd: open /Users/case/Library/Application Support/Lnd/lnd.conf: no such file or directory',
- 'lnd: 12:51:52 2016-10-09 [ERR] RPCS: unable to open channel to lightningID(303239306266343534663462393562616639323237383031333031623333316533356434373763366236653766333661353939393833616535383734376233383238) nor peerID(0): unable to find peer lightningID([48 50 57 48 98 102 52 53 52 102 52 98 57 53 98 97 102 57 50 50 55 56 48 49 51 48 49 98 51 51 49 101]), peerID(0)',
-]
diff --git a/packages/lightning-core/fixtures/transactions.js b/packages/lightning-core/fixtures/transactions.js
deleted file mode 100644
index de115ac07..000000000
--- a/packages/lightning-core/fixtures/transactions.js
+++ /dev/null
@@ -1,42 +0,0 @@
-export default [
- {
- id: '0',
- from: 'case@casesandberg.com',
- to: 'joseph@lightning.network',
- amount: 0.0021456,
- status: 'in-progress',
- description: 'For a really cool book',
- }, {
- id: '1',
- from: 'case@casesandberg.com',
- to: 'testing@lightning.network',
- amount: 0.0001136,
- status: 'in-progress',
- description: 'Test Transcation',
- }, {
- id: '2',
- from: 'stark@lightning.network',
- to: 'case@casesandberg.com',
- amount: 1.44395684,
- status: 'complete',
- }, {
- id: '3',
- from: 'case@casesandberg.com',
- to: 'joseph@lightning.network',
- amount: 0.048684357,
- status: 'complete',
- }, {
- id: '4',
- from: 'stark@lightning.network',
- to: 'case@casesandberg.com',
- amount: 0.29121235,
- status: 'complete',
- description: 'Lunch',
- }, {
- id: '5',
- from: 'case@casesandberg.com',
- to: 'joseph@lightning.network',
- amount: 0.23118217,
- status: 'complete',
- },
-]
diff --git a/packages/lightning-core/fixtures/wallet.js b/packages/lightning-core/fixtures/wallet.js
deleted file mode 100644
index da861243a..000000000
--- a/packages/lightning-core/fixtures/wallet.js
+++ /dev/null
@@ -1,9 +0,0 @@
-export default {
- id: 0,
- identity: 'case@casesandberg.com',
- amount: {
- blockchain: 149966113712,
- channels: 3823424212,
- },
- address: '1DkyBEKt5S2GDtv7aQw6rQepAvnsRyHoYM',
-}
diff --git a/packages/lightning-core/helpers/buffers.js b/packages/lightning-core/helpers/buffers.js
new file mode 100644
index 000000000..3600bbbb1
--- /dev/null
+++ b/packages/lightning-core/helpers/buffers.js
@@ -0,0 +1 @@
+export const toHash = hash => new Buffer(hash, 'base64').toString('hex')
diff --git a/packages/lightning-core/helpers/currencies.js b/packages/lightning-core/helpers/currencies.js
index 0c9bcd130..4fab90cc4 100644
--- a/packages/lightning-core/helpers/currencies.js
+++ b/packages/lightning-core/helpers/currencies.js
@@ -8,6 +8,8 @@ export const removeCommas = (string = 0) => {
return _.isString(string) ? Number(string.replace(/[^0-9]/g, '')) : string
}
+export const enforceNumbers = (string = '') => string.replace(/[^0-9]/g, '')
+
const toBTC = (sat) => {
return removeCommas(sat) / 100000000
}
@@ -46,6 +48,8 @@ const currencies = {
},
}
+export const getAll = () => _.mapValues(currencies, 'code')
+
export default {
find: (id) => {
return currencies[id] || { sign: 'MISSING', format: () => { return 'MISSING' } }
diff --git a/packages/lightning-core/helpers/errors.js b/packages/lightning-core/helpers/errors.js
index f88d557e0..e2d532a38 100644
--- a/packages/lightning-core/helpers/errors.js
+++ b/packages/lightning-core/helpers/errors.js
@@ -1,4 +1,3 @@
-
export const GET_ACCOUNT_FAILURE = 'Cannot Find PubKey'
export const WALLETS_FETCH_FAILURE = 'Error Getting Wallet Info'
diff --git a/packages/lightning-core/helpers/index.js b/packages/lightning-core/helpers/index.js
index c9c05f22b..3998aa016 100644
--- a/packages/lightning-core/helpers/index.js
+++ b/packages/lightning-core/helpers/index.js
@@ -1 +1,5 @@
-export { default as currencies } from './currencies' // eslint-disable-line import/prefer-default-export
+export { default as currencies } from './currencies'
+
+export * from './buffers'
+export * from './paymentRequest'
+export * from './wallet'
diff --git a/packages/lightning-core/helpers/paymentRequest.js b/packages/lightning-core/helpers/paymentRequest.js
new file mode 100644
index 000000000..52da6f101
--- /dev/null
+++ b/packages/lightning-core/helpers/paymentRequest.js
@@ -0,0 +1,9 @@
+const prefix = 'lightning:'
+
+export const decoratePaymentRequest = (pr) => {
+ return prefix + pr
+}
+
+export const sanitizePaymentRequest = (pr) => {
+ return pr.replace(prefix, '')
+}
diff --git a/packages/lightning-core/helpers/redux.js b/packages/lightning-core/helpers/redux.js
deleted file mode 100644
index cd20da9ed..000000000
--- a/packages/lightning-core/helpers/redux.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import _ from 'lodash'
-
-export const scopeStateToSelectors = (selectorsMap) => {
- return _.reduce(selectorsMap, (allScopedSelectors, selectors, scope) => (
- _.reduce(selectors, (scopedSelectors, selector, selectorName) => ({
- ...scopedSelectors,
- [selectorName]: (state, ...rest) => selector(state[scope], ...rest),
- }), allScopedSelectors)
- ), {})
-}
diff --git a/packages/lightning-core/helpers/wallet.js b/packages/lightning-core/helpers/wallet.js
index 25c7c3f9a..9d9187f33 100644
--- a/packages/lightning-core/helpers/wallet.js
+++ b/packages/lightning-core/helpers/wallet.js
@@ -1,3 +1 @@
-export function total({ blockchain, channels}) { // eslint-disable-line
- return blockchain + channels
-}
+export const total = ({ wallet = 0, channel = 0 }) => wallet + channel
diff --git a/packages/lightning-core/index.js b/packages/lightning-core/index.js
index 0d200e0d2..027ad8639 100644
--- a/packages/lightning-core/index.js
+++ b/packages/lightning-core/index.js
@@ -1,12 +1,10 @@
-export * from './components/common'
-
-export { default as ChannelsList } from './components/channels/ChannelsList'
-
-export { default as NavLinks } from './components/nav/NavLinks'
-export { default as NavFooter } from './components/nav/NavFooter'
-
-export { default as TransactionsList } from './components/transactions/TransactionsList'
-export { default as TransactionsNavBar } from './components/transactions/TransactionsNavBar'
-
-export { default as WalletsList } from './components/wallet/WalletsList'
-export { default as WalletsListCompact } from './components/wallet/WalletsListCompact'
+export { default as AccountsPage } from './accounts'
+export { CreateChannelPage } from './accounts'
+export { default as PayPage } from './pay'
+export { default as RequestPage } from './request'
+export { default as SettingsPage } from './settings'
+export { default as TransactionsPage } from './transactions'
+export { default as Sidebar } from './common/Sidebar'
+export { default as Streams } from './common/Streams'
+
+export { reducer, selectors } from './reducer'
diff --git a/packages/lightning-core/package.json b/packages/lightning-core/package.json
index 4de11e52a..66bfb5b26 100644
--- a/packages/lightning-core/package.json
+++ b/packages/lightning-core/package.json
@@ -1,6 +1,6 @@
{
"name": "lightning-core",
- "version": "1.9.0",
+ "version": "1.9.1",
"description": "",
"main": "index.js",
"scripts": {
@@ -9,11 +9,20 @@
"author": "case ",
"license": "MIT",
"dependencies": {
- "lightning-components": "^0.1.0",
+ "electron": "^1.6.2",
+ "lightning-components": "^0.1.1",
+ "lightning-forms": "^0.1.0",
+ "lightning-notifications": "^0.1.1",
+ "lightning-popup": "^0.1.0",
+ "lightning-store": "^0.1.1",
"lodash": "^4.16.2",
- "react": "^15.3.2",
- "react-redux": "^4.4.5",
- "react-router": "^4.0.0-alpha.5",
- "reactcss": "^1.0.8"
+ "react": "^15.4.1",
+ "react-infinite": "^0.10.0",
+ "react-redux": "^4.4.6",
+ "react-router-dom": "^4.0.0",
+ "reactcss": "^1.0.8",
+ "redux": "^3.6.0",
+ "redux-grpc-middleware": "^0.1.1",
+ "redux-selector": "^0.1.0"
}
}
diff --git a/packages/lightning-core/pay/index.js b/packages/lightning-core/pay/index.js
new file mode 100644
index 000000000..91ee02fcb
--- /dev/null
+++ b/packages/lightning-core/pay/index.js
@@ -0,0 +1,97 @@
+/* eslint-disable global-require, no-console */
+
+import React from 'react'
+import { connect } from 'react-redux'
+import { Form, actions as formActions } from 'lightning-forms'
+import { actions } from './reducer'
+import { remote } from 'electron'
+import { actions as accountsActions } from '../accounts'
+import { CurrencyInput, Head, Input, Page } from '../common'
+import { sanitizePaymentRequest } from '../helpers'
+
+const { Menu, MenuItem } = remote
+
+export const Pay = ({ onMakePayment, onDecodePaymentRequest, onEditForm,
+ onFetchAccount, onFetchChannels }) => {
+ const fields = [
+ {
+ name: 'address',
+ placeholder: 'Payment Request / Bitcoin Address',
+ required: true,
+ component: Input,
+
+ },
+ {
+ name: 'amount',
+ placeholder: 'Amount',
+ required: true,
+ component: CurrencyInput,
+ },
+ ]
+
+ const menu = new Menu()
+ menu.append(new MenuItem({ label: 'Paste', role: 'paste' }))
+ const handleMenu = () => menu.popup(remote.getCurrentWindow())
+
+ const handleSuccess = ({ address, amount }, clear) => {
+ onMakePayment({ address, amount })
+ .then(() => {
+ onFetchAccount()
+ onFetchChannels()
+ clear()
+ })
+ .catch(console.error)
+ }
+
+ const handleError = (errors) => {
+ console.log('error', errors)
+ }
+
+ const handleChange = (change) => {
+ fields[1].disabled = false
+ if (change.address) {
+ const paymentRequest = sanitizePaymentRequest(change.address)
+ onDecodePaymentRequest({ paymentRequest })
+ .then((decoded) => {
+ const amount = decoded.num_satoshis
+ // Disable the amount field when using payment requests
+ fields[1].disabled = true
+ onEditForm('pay', { amount })
+ })
+ .catch(console.error)
+ }
+ }
+
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default connect(
+ () => ({}), {
+ onMakePayment: actions.makePayment,
+ onDecodePaymentRequest: actions.decodePaymentRequest,
+ onEditForm: formActions.editForm,
+ onFetchAccount: accountsActions.fetchAccount,
+ onFetchChannels: accountsActions.fetchChannels,
+ },
+)(Pay)
+
+export { default as reducer, actions, selectors } from './reducer'
diff --git a/packages/lightning-core/pay/reducer.js b/packages/lightning-core/pay/reducer.js
new file mode 100644
index 000000000..a7ab4a3d6
--- /dev/null
+++ b/packages/lightning-core/pay/reducer.js
@@ -0,0 +1,94 @@
+import { GRPC } from 'redux-grpc-middleware'
+import { actions as notificationActions } from 'lightning-notifications'
+import { actions as accountsActions } from '../accounts'
+import { sanitizePaymentRequest } from '../helpers'
+
+export const DECODE_PAYMENT_REQUEST = 'PAY/DECODE_PAYMENT_REQUEST'
+export const CHECK_PAYMENT_REQUEST = 'PAY/CHECK_PAYMENT_REQUEST'
+export const LIGHTNING_PAYMENT = 'PAY/LIGHTNING_PAYMENT'
+export const BITCOIN_PAYMENT = 'PAY/BITCOIN_PAYMENT'
+export const SUBSCRIBE_PAYMENT = 'PAY/SUBSCRIBE_PAYMENT'
+
+const initialState = {
+
+}
+
+export default (state = initialState, action) => {
+ switch (action.type) {
+ default: return state
+ }
+}
+
+export const actions = {
+ decodePaymentRequest: ({ paymentRequest }) => ({
+ [GRPC]: {
+ method: 'decodePayReq',
+ body: {
+ pay_req: paymentRequest,
+ },
+ types: DECODE_PAYMENT_REQUEST,
+ },
+ }),
+ makePayment: ({ address, amount }) => (dispatch) => {
+ return new Promise((resolve, reject) => {
+ const resolveSuccess = () => {
+ dispatch(notificationActions.addNotification('Payment Sent'))
+ dispatch(accountsActions.fetchChannels())
+ dispatch(accountsActions.fetchBalances())
+ dispatch(accountsActions.fetchAccount())
+ resolve('Payment Sent')
+ }
+ const rejectError = (err) => {
+ dispatch(notificationActions.addNotification(err.message))
+ reject(err.message)
+ }
+ const paymentRequest = sanitizePaymentRequest(address)
+
+ dispatch(actions.decodePaymentRequest({ paymentRequest }))
+ .then(() => {
+ const payments = dispatch(actions.sendPayment())
+ payments.on('data', (payment) => {
+ if (payment.payment_error === '') {
+ resolveSuccess()
+ } else {
+ // TODO(roasbeef): need to switch and properly display errors
+ rejectError({ message: 'Payment route failure' })
+ }
+ })
+ payments.on('error', rejectError)
+ payments.write({ payment_request: paymentRequest })
+ })
+ .catch(() => {
+ dispatch(actions.sendCoins({ address, amount }))
+ .then(resolve)
+ .catch(rejectError)
+ })
+ })
+ },
+ sendCoins: ({ address, amount }) => ({
+ [GRPC]: {
+ method: 'sendCoins',
+ body: {
+ addr: address,
+ amount,
+ },
+ types: BITCOIN_PAYMENT,
+ },
+ }),
+ sendPayment: () => ({
+ [GRPC]: {
+ method: 'sendPayment',
+ types: LIGHTNING_PAYMENT,
+ stream: true,
+ },
+ }),
+ subscribePayments: () => ({
+ [GRPC]: {
+ method: 'subscribePayments',
+ types: SUBSCRIBE_PAYMENT,
+ stream: true,
+ },
+ }),
+}
+
+export const selectors = {}
diff --git a/packages/lightning-core/reducer.js b/packages/lightning-core/reducer.js
new file mode 100644
index 000000000..208d6e14b
--- /dev/null
+++ b/packages/lightning-core/reducer.js
@@ -0,0 +1,17 @@
+import { combineReducers } from 'redux'
+
+import { reducer as accounts } from './accounts'
+import { reducer as pay } from './pay'
+import { reducer as request } from './request'
+import { reducer as settings } from './settings'
+import { reducer as transactions } from './transactions'
+
+export const reducer = combineReducers({
+ accounts,
+ pay,
+ request,
+ settings,
+ transactions,
+})
+
+export { selectors } from './selectors'
diff --git a/packages/lightning-core/reducers/channel.js b/packages/lightning-core/reducers/channel.js
deleted file mode 100644
index 260ec0ef7..000000000
--- a/packages/lightning-core/reducers/channel.js
+++ /dev/null
@@ -1,15 +0,0 @@
-export const CREATE_CHANNEL = 'CHANNEL/CREATE_CHANNEL'
-
-export default function channels(state = {}, action) {
- switch (action.type) {
- case CREATE_CHANNEL:
- return {
- total: action.data.amount,
- localAllocation: action.data.amount,
- remoteAllocation: 0,
- remotePubKey: action.data.pubKey,
- status: 'pending',
- }
- default: return state
- }
-}
diff --git a/packages/lightning-core/reducers/channels.js b/packages/lightning-core/reducers/channels.js
deleted file mode 100644
index 9e11e3c41..000000000
--- a/packages/lightning-core/reducers/channels.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import _ from 'lodash'
-import { GRPC } from 'redux-grpc-middlware'
-import { actions as notificationsActions } from 'lightning-notifications'
-import channel, * as CHANNEL from './channel'
-
-export const GET_CHANNELS = 'CHANNELS/GET_CHANNELS'
-export const FILL_FORM = 'CHANNELS/FILL_FORM'
-export const LIST_PEERS = 'CHANNELS/LIST_PEERS'
-
-export const OPEN_CHANNEL_REQUEST = 'CHANNELS/OPEN_CHANNEL_REQUEST'
-export const OPEN_CHANNEL = 'CHANNELS/OPEN_CHANNEL'
-export const OPEN_CHANNEL_FAILURE = 'CHANNELS/OPEN_CHANNEL_FAILURE'
-
-export const CONNECT_PEER_REQUEST = 'CHANNELS/CONNECT_PEER_REQUEST'
-export const CONNECT_PEER = 'CHANNELS/CONNECT_PEER'
-export const CONNECT_PEER_FAILURE = 'CHANNELS/CONNECT_PEER_FAILURE'
-
-export default function channels(state = [], action) {
- switch (action.type) {
- case GET_CHANNELS:
- return _.map(action.listChannels.channels, c => ({
- total: parseInt(c.local_balance, 10) + parseInt(c.remote_balance, 10),
- localAllocation: parseInt(c.local_balance, 10),
- remoteAllocation: parseInt(c.remote_balance, 10),
- remotePubKey: c.remote_pubkey,
- status: 'open',
- }))
- case CHANNEL.CREATE_CHANNEL:
- return [...state, channel({}, action)]
- default: return state
- }
-}
-
-export const actions = {
- fillCreateForm: create => ({ type: FILL_FORM, create }),
-
- getChannels: () => ({
- [GRPC]: {
- method: 'listChannels',
- types: [null, GET_CHANNELS, null],
- },
- }),
-
- openChannel: (pubKey, amount) => ({
- [GRPC]: {
- method: 'openChannel',
- body: {
- node_pubkey_string: pubKey,
- local_funding_amount: amount,
- num_confs: 1,
- },
- types: [OPEN_CHANNEL_REQUEST, OPEN_CHANNEL, OPEN_CHANNEL_FAILURE],
- },
- }),
-
- listPeers: () => ({
- [GRPC]: {
- method: 'listPeers',
- types: [null, LIST_PEERS],
- },
- }),
-
- connectPeer: (host, pubkey) => ({
- [GRPC]: {
- method: 'connectPeer',
- body: {
- addr: { host, pubkey },
- },
- types: [CONNECT_PEER_REQUEST, CONNECT_PEER, CONNECT_PEER_FAILURE],
- },
- }),
-
- createChannel: data => (dispatch) => {
- const [pubkey, host] = data.host && data.host.split('@')
-
- dispatch(actions.listPeers())
- .then(({ listPeers }) => {
- const peer = _.find(listPeers.peers, { pub_key: pubkey })
-
- if (peer) {
- dispatch(actions.openChannel(pubkey, data.amount))
- } else {
- dispatch(actions.connectPeer(host, pubkey))
- .then(() => {
- dispatch(actions.openChannel(pubkey, data.amount))
- })
- .catch(err => dispatch(notificationsActions.addNotification(err.message)))
- }
- })
- .catch(err => dispatch(notificationsActions.addNotification(err.message)))
- },
-}
-
-export const selectors = {
- getChannels: state => state,
-}
diff --git a/packages/lightning-core/reducers/payment.js b/packages/lightning-core/reducers/payment.js
deleted file mode 100644
index 0aed8473c..000000000
--- a/packages/lightning-core/reducers/payment.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import { GRPC } from 'redux-grpc-middlware'
-
-export const SEND_BITCOIN = 'PAYMENT/SEND_BITCOIN'
-export const SET_BITCOIN_ADDRESS = 'PAYMENT/SET_BITCOIN_ADDRESS'
-
-export const CHANGE_BITCOIN_FORM = 'PAYMENT/CHANGE_BITCOIN_FORM'
-export const CHANGE_LIGHTNING_FORM = 'PAYMENT/CHANGE_LIGHTNING_FORM'
-export const CHANGE_LIGHTNING_SEND_URI = 'PAYMENT/CHANGE_LIGHTNING_SEND_URI'
-
-export const SEND_PAYMENT_REQUEST = 'CHANNELS/SEND_PAYMENT_REQUEST'
-export const SEND_PAYMENT = 'CHANNELS/SEND_PAYMENT'
-export const SEND_PAYMENT_FAILURE = 'CHANNELS/SEND_PAYMENT_FAILURE'
-
-export const CREATE_INVOICE_REQUEST = 'PAYMENT/CREATE_INVOICE_REQUEST'
-export const CREATE_INVOICE = 'PAYMENT/CREATE_INVOICE'
-export const CREATE_INVOICE_FAILURE = 'PAYMENT/CREATE_INVOICE_FAILURE'
-
-const initialState = {
- bitcoinAddress: '',
-}
-
-export default function payment(state = initialState, action) {
- switch (action.type) {
- case SET_BITCOIN_ADDRESS:
- return { ...state, bitcoinAddress: action.user.address }
- default: return state
- }
-}
-
-export const actions = {
- newWitnessAddress: () => ({
- [GRPC]: {
- method: 'newWitnessAddress',
- types: [null, SET_BITCOIN_ADDRESS],
- model: 'user',
- },
- }),
-
- sendCoins: ({ to, amount }) => ({
- [GRPC]: {
- method: 'sendCoins',
- body: {
- addr: to,
- amount,
- },
- types: [null, SEND_BITCOIN],
- model: 'transaction',
- },
- }),
-
- sendLightning: (remotePubKey, amount, paymentHash) => ({
- [GRPC]: {
- method: 'sendPayment',
- body: {
- amt: amount,
- dest_string: remotePubKey,
- payment_hash: paymentHash,
- },
- types: [SEND_PAYMENT_REQUEST, SEND_PAYMENT, SEND_PAYMENT_FAILURE],
- },
- }),
-
- requestLightning: (form, pubkey) => ({
- [GRPC]: {
- method: 'addInvoice',
- body: {
- memo: form.note,
- value: form.amount,
- },
- types: [CREATE_INVOICE_REQUEST, CREATE_INVOICE, CREATE_INVOICE_FAILURE],
- model: 'invoice',
- passthrough: { pubkey, amount: form.amount },
- },
- }),
-
- changeBitcoinForm: data => ({ type: CHANGE_BITCOIN_FORM, data }),
- changeLightningForm: data => ({ type: CHANGE_LIGHTNING_FORM, data }),
- changeSendURI: uri => ({ type: CHANGE_LIGHTNING_SEND_URI, uri }),
-}
-
-export const selectors = {
- getBitcoinAddress: state => state.bitcoinAddress,
-}
diff --git a/packages/lightning-core/reducers/transaction.js b/packages/lightning-core/reducers/transaction.js
deleted file mode 100644
index a4e148b79..000000000
--- a/packages/lightning-core/reducers/transaction.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import * as TRANSACTIONS from './transactions'
-
-export default function transaction(state, action) {
- switch (action.type) {
- case TRANSACTIONS.STREAMING_TRANSACTION:
- case TRANSACTIONS.GET_BITCOIN: {
- const fromYou = state.amount < 0
- return {
- id: state.tx_hash,
- from: fromYou ? 'You' : state.tx_hash,
- to: fromYou ? state.tx_hash : 'You',
- amount: state.amount * 1000000000,
- status: 'complete',
- date: parseInt(state.time_stamp, 10),
- }
- }
- case TRANSACTIONS.STREAMING_INVOICE:
- case TRANSACTIONS.GET_LIGHTNING: {
- const hash = new Buffer(state.r_preimage, 'base64').toString('hex')
- return {
- id: hash,
- from: hash,
- to: 'You',
- amount: state.value,
- status: state.settled ? 'complete' : 'in-progress',
- description: state.memo,
- date: parseInt(state.creation_date, 10),
- }
- }
- default: return state
- }
-}
diff --git a/packages/lightning-core/reducers/transactions.js b/packages/lightning-core/reducers/transactions.js
deleted file mode 100644
index 6c4b10c2c..000000000
--- a/packages/lightning-core/reducers/transactions.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/* eslint-disable no-param-reassign */
-import _ from 'lodash'
-import { GRPC } from 'redux-grpc-middlware'
-import transaction from './transaction'
-
-export const GET_TRANSACTIONS_REQUEST = 'TRANSACTIONS/GET_TRANSACTIONS_REQUEST'
-
-export const GET_BITCOIN = 'TRANSACTIONS/GET_BITCOIN'
-export const GET_LIGHTNING = 'TRANSACTIONS/GET_LIGHTNING'
-
-export const STREAMING_TRANSACTION = 'TRANSACTIONS/STREAMING_TRANSACTION'
-export const STREAMING_INVOICE = 'TRANSACTIONS/STREAMING_INVOICE'
-
-export default function transactions(state = {}, action) {
- switch (action.type) {
- case GET_BITCOIN:
- return _.reduce(action.bitcoin.transactions, (all, t) => {
- all[t.tx_hash] = transaction(t, action)
- return all
- }, { ...state })
-
- case GET_LIGHTNING:
- return _.reduce(action.lightning.invoices, (all, t) => {
- const id = new Buffer(t.r_preimage, 'base64').toString('hex')
- all[id] = transaction(t, action)
- return all
- }, { ...state })
-
- case STREAMING_TRANSACTION:
- return {
- ...state,
- [action.transaction.tx_hash]: transaction(action.transaction, action),
- }
- case STREAMING_INVOICE: {
- const id = new Buffer(action.invoice.r_preimage, 'base64').toString('hex')
- return {
- ...state,
- [id]: transaction(action.invoice, action),
- }
- }
- default: return state
- }
-}
-
-export const actions = {
- getBitcoinTransactions: () => ({
- [GRPC]: {
- method: 'getTransactions',
- types: [null, GET_BITCOIN],
- model: 'bitcoin',
- },
- }),
-
- getLightningTransactions: () => ({
- [GRPC]: {
- method: 'listInvoices',
- types: [null, GET_LIGHTNING],
- model: 'lightning',
- },
- }),
-
- getTransactions: () => (dispatch) => {
- dispatch(actions.getBitcoinTransactions())
- dispatch(actions.getLightningTransactions())
- },
-
- subscribeTransactions: () => ({
- [GRPC]: {
- method: 'subscribeTransactions',
- stream: true,
- },
- }),
-
- subscribeInvoices: () => ({
- [GRPC]: {
- method: 'subscribeInvoices',
- stream: true,
- },
- }),
-
- updateTransaction: transaction => ({ type: STREAMING_TRANSACTION, transaction }), // eslint-disable-line no-shadow, max-len
- updateInvoice: invoice => ({ type: STREAMING_INVOICE, invoice }),
-}
-
-export const selectors = {
- getRecentTransactions: (state) => {
- return _.orderBy(state, 'date', 'desc')
- },
- getRecentTransactionsByStatus: (state, status) => {
- const recent = selectors.getRecentTransactions(state)
- const filtered = status === 'recent' ? recent : _.filter(recent, { status })
- return _.take(filtered, 30)
- },
-}
diff --git a/packages/lightning-core/reducers/ui.js b/packages/lightning-core/reducers/ui.js
deleted file mode 100644
index cf3ab49bd..000000000
--- a/packages/lightning-core/reducers/ui.js
+++ /dev/null
@@ -1,127 +0,0 @@
-import { GRPC } from 'redux-grpc-middlware'
-import * as PAYMENT from './payment'
-import * as CHANNELS from './channels'
-
-export const CHANGE_CURRENCY = 'UI/CHANGE_CURRENCY'
-
-export const GET_ACCOUNT_REQUEST = 'UI/GET_ACCOUNT_REQUEST'
-export const GET_ACCOUNT = 'UI/GET_ACCOUNT'
-export const GET_ACCOUNT_FAILURE = 'UI/GET_ACCOUNT_FAILURE'
-
-export const SUBSCRIBE_TRANSACTIONS = 'UI/SUBSCRIBE_TRANSACTIONS'
-
-export const initialState = {
- currency: 'satoshi',
- account: {
- pubKey: '',
- lnid: '',
- syncedToChain: true,
- },
- channelsCreateForm: {
- host: '',
- amount: '',
- },
- sendBitcoinForm: {
- to: '',
- amount: '',
- note: '',
- },
- sendLightningForm: {
- amount: 0,
- pubkey: '',
- rHash: '',
- },
- requestLightningForm: {
- amount: '',
- note: '',
- uri: '',
- },
- sendLightningURI: '',
-}
-
-export default function ui(state = initialState, action) {
- switch (action.type) {
- case PAYMENT.SEND_PAYMENT:
- case PAYMENT.SEND_BITCOIN:
- case 'ROUTE_CHANGE':
- return {
- ...state,
- requestLightningForm: initialState.requestLightningForm,
- sendLightningForm: initialState.sendLightningForm,
- sendBitcoinForm: initialState.sendBitcoinForm,
- channelsCreateForm: initialState.channelsCreateForm,
- sendLightningURI: initialState.sendLightningURI,
- }
- case CHANGE_CURRENCY:
- return { ...state, currency: action.currency }
- case CHANNELS.FILL_FORM:
- return { ...state, channelsCreateForm: action.create }
- case PAYMENT.CHANGE_BITCOIN_FORM:
- return { ...state, sendBitcoinForm: { ...state.sendBitcoinForm, ...action.data } }
- case PAYMENT.CHANGE_LIGHTNING_FORM:
- return { ...state, requestLightningForm: { ...state.requestLightningForm, ...action.data } }
- case PAYMENT.CHANGE_LIGHTNING_SEND_URI: {
- const [, amount, pubkey, rHash] = action.uri.split(',')
- return {
- ...state,
- requestLightningForm: initialState.requestLightningForm,
- sendLightningURI: action.uri,
- sendLightningForm: { amount, pubkey, rHash },
- }
- }
- case PAYMENT.CREATE_INVOICE: {
- const rHashHex = new Buffer(action.invoice.r_hash, 'base64').toString('hex')
- const uri = `lightning,${ action.amount },${ action.pubkey },${ rHashHex }`
- return {
- ...state,
- requestLightningForm: {
- amount: '',
- note: '',
- uri,
- },
- }
- }
- case GET_ACCOUNT:
- return {
- ...state,
- account: {
- pubKey: action.account.identity_pubkey,
- lnid: action.account.lightning_id,
- syncedToChain: true || action.account.synced_to_chain,
- },
- }
- case GET_ACCOUNT_FAILURE:
- return { ...state, account: { pubKey: 'No Pubkey' } }
- default: return state
- }
-}
-
-export const actions = {
- changeCurrency: currency => ({ type: CHANGE_CURRENCY, currency }),
-
- fetchAccount: () => ({
- [GRPC]: {
- method: 'getInfo',
- types: [GET_ACCOUNT_REQUEST, GET_ACCOUNT, GET_ACCOUNT_FAILURE],
- model: 'account',
- },
- }),
-
- subscribeTransactions: () => ({
- [GRPC]: {
- method: 'subscribeTransactions',
- types: [null, SUBSCRIBE_TRANSACTIONS, null],
- },
- }),
-}
-
-export const selectors = {
- getSyncedToChain: state => state.account.syncedToChain,
- getCurrency: state => state.currency,
- getAccountInfo: state => state.account,
- getSendLightningForm: state => state.sendLightningForm,
- getChannelsCreateForm: state => state.channelsCreateForm,
- getSendBitcoinForm: state => state.sendBitcoinForm,
- getRequestLightningForm: state => state.requestLightningForm,
- getSendLightningURI: state => state.sendLightningURI,
-}
diff --git a/packages/lightning-core/reducers/wallet.js b/packages/lightning-core/reducers/wallet.js
deleted file mode 100644
index 3d2a6621b..000000000
--- a/packages/lightning-core/reducers/wallet.js
+++ /dev/null
@@ -1,28 +0,0 @@
-export const FETCH_BALANCES = 'WALLET/FETCH_BALANCES'
-export const SET_AMOUNT = 'WALLET/SET_AMOUNT'
-
-export const initialState = {
- id: 0,
- identity: '',
- amount: {
- blockchain: 0,
- channels: 0,
- },
- address: '',
-}
-
-export default function wallet(state = initialState, action) {
- switch (action.type) {
- case SET_AMOUNT: {
- const amount = {
- blockchain: action.amount.walletBalance.balance * 100000000 || 0,
- channels: action.amount.channelBalance.balance || 0,
- }
- return {
- ...state,
- amount: { ...state.amount, ...amount },
- }
- }
- default: return state
- }
-}
diff --git a/packages/lightning-core/reducers/wallets.js b/packages/lightning-core/reducers/wallets.js
deleted file mode 100644
index e266768dc..000000000
--- a/packages/lightning-core/reducers/wallets.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import { GRPC } from 'redux-grpc-middlware'
-import _ from 'lodash'
-import { combineReducers } from 'redux'
-import wallet, * as WALLET from './wallet'
-
-export const FETCH = 'WALLETS/FETCH'
-export const SWITCH_WALLET = 'WALLETS/SWITCH_WALLET'
-
-export function wallets(state = [WALLET.initialState], action) {
- switch (action.type) {
- case WALLET.SET_AMOUNT:
- return [
- wallet(state[0], action),
- ]
- default: return state
- }
-}
-
-const initialWalletState = {
- activeWalletIndex: 0,
-}
-
-export function ui(state = initialWalletState, action) {
- switch (action.type) {
- case SWITCH_WALLET:
- return { ...state, activeWalletIndex: action.activeWalletIndex }
- default: return state
- }
-}
-
-export default combineReducers({
- wallets,
- ui,
-})
-
-export const actions = {
- walletBalance: () => ({
- [GRPC]: {
- method: 'walletBalance',
- },
- }),
-
- channelBalance: () => ({
- [GRPC]: {
- method: 'channelBalance',
- },
- }),
-
- fetchBalances: () => (dispatch) => {
- Promise.all([
- dispatch(actions.walletBalance()),
- dispatch(actions.channelBalance()),
- ])
- .then((results) => {
- const amount = _.reduce(results, _.extend)
- dispatch({ type: WALLET.SET_AMOUNT, amount })
- })
- },
- switchWallet: activeWalletIndex => ({ type: SWITCH_WALLET, activeWalletIndex }),
-}
-
-export const selectors = {
- getWallets: state => state.wallets,
- getActiveWallet: state => state.wallets[state.ui.activeWalletIndex],
- getActiveWalletIndex: state => state.ui.activeWalletIndex,
-}
diff --git a/packages/lightning-core/request/BitcoinWallet.js b/packages/lightning-core/request/BitcoinWallet.js
new file mode 100644
index 000000000..61a161f90
--- /dev/null
+++ b/packages/lightning-core/request/BitcoinWallet.js
@@ -0,0 +1,90 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+import { remote } from 'electron'
+import { Box, Text } from 'lightning-components'
+import { Popup } from 'lightning-popup'
+import { Icon, QRCode } from 'lightning-components'
+import { Input } from '../common'
+
+const QR_CODE = 'QR_CODE'
+
+const { Menu, MenuItem } = remote
+
+export class BitcoinWallet extends React.Component {
+ componentDidMount() { this.props.onFetchAddress() }
+
+ render() {
+ const { address, onSuccess, onShowQR } = this.props
+
+ const styles = reactCSS({
+ 'default': {
+ wrap: {
+ borderTop: '1px solid #ddd',
+ padding: 20,
+ display: 'flex',
+ alignItems: 'center',
+ },
+ label: {
+ marginTop: 10,
+ marginBottom: 10,
+ borderRight: '1px solid #ddd',
+ paddingLeft: 20,
+ paddingRight: 20,
+ display: 'flex',
+ alignItems: 'center',
+ color: '#999',
+ userSelect: 'none',
+ cursor: 'default',
+ },
+ icon: {
+ paddingLeft: 20,
+ cursor: 'pointer',
+ color: '#666',
+ },
+ qrPopup: {
+ background: '#fff',
+ borderRadius: 2,
+ width: 300,
+ height: 300,
+ },
+ },
+ })
+
+ const menu = new Menu()
+ menu.append(new MenuItem({ label: 'Copy', role: 'copy' }))
+ menu.append(new MenuItem({ label: 'Select All', role: 'selectall' }))
+ const handleMenu = () => menu.popup(remote.getCurrentWindow())
+
+ const handleCopy = () => onSuccess('Copied to Clipboard')
+ const handleClick = () => onShowQR(QR_CODE)
+
+ const label = (
+ Wallet Address
+ )
+
+ return (
+
+ )
+ }
+}
+
+export default BitcoinWallet
diff --git a/packages/lightning-core/request/PaymentRequestPopup.js b/packages/lightning-core/request/PaymentRequestPopup.js
new file mode 100644
index 000000000..649715126
--- /dev/null
+++ b/packages/lightning-core/request/PaymentRequestPopup.js
@@ -0,0 +1,79 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+import { remote } from 'electron'
+import { Popup } from 'lightning-popup'
+import { QRCode } from 'lightning-components'
+import { Head, Input } from '../common'
+
+const { Menu, MenuItem } = remote
+
+export const POPUP_NAME = 'paymentRequest'
+
+export const PaymentRequestPopup = ({ paymentRequest, closePopup }) => {
+ const styles = reactCSS({
+ 'default': {
+ box: {
+ background: '#fff',
+ borderRadius: 2,
+ width: 390,
+ padding: 30,
+ boxShadow: '0 0 4px rgba(0,0,0,0.2), 0 8px 12px rgba(0,0,0,0.2)',
+ },
+ copy: {
+ marginTop: 10,
+ marginBottom: 10,
+ borderLeft: '1px solid #ddd',
+ paddingLeft: 20,
+ paddingRight: 20,
+ display: 'flex',
+ alignItems: 'center',
+ color: '#4990E2',
+ cursor: 'pointer',
+ },
+ qrPopup: {
+ background: '#fff',
+ borderRadius: 2,
+ width: 300,
+ height: 300,
+ marginLeft: 'auto',
+ marginRight: 'auto',
+ paddingBottom: 10,
+ }
+ },
+ })
+ const menu = new Menu()
+ menu.append(new MenuItem({ label: 'Copy', role: 'copy' }))
+ menu.append(new MenuItem({ label: 'Select All', role: 'selectall' }))
+ const handleMenu = () => menu.popup(remote.getCurrentWindow())
+
+ const handleCopied = () => closePopup(POPUP_NAME)
+
+ const copyButton = (
+ Copy
+ )
+
+ return (
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default PaymentRequestPopup
diff --git a/packages/lightning-core/request/index.js b/packages/lightning-core/request/index.js
new file mode 100644
index 000000000..6e49a4e7c
--- /dev/null
+++ b/packages/lightning-core/request/index.js
@@ -0,0 +1,99 @@
+/* eslint-disable global-require, no-console */
+
+import React from 'react'
+import { Form } from 'lightning-forms'
+import { actions as popupActions } from 'lightning-popup'
+import { store } from 'lightning-store'
+import { connect } from 'react-redux'
+import { actions as notificationActions } from 'lightning-notifications'
+import { actions } from './reducer'
+import { CurrencyInput, Head, Input, Page } from '../common'
+import PaymentRequestPopup, { POPUP_NAME } from './PaymentRequestPopup'
+import BitcoinWallet from './BitcoinWallet'
+
+export const Pay = ({ showPopup, closePopup, paymentRequest, address,
+ onFetchAddress, onGeneratePaymentRequest, onSuccess }) => {
+ const fields = [
+ {
+ name: 'amount',
+ placeholder: 'Amount',
+ required: true,
+ component: CurrencyInput,
+ },
+ {
+ name: 'note',
+ placeholder: 'Note',
+ component: Input,
+ },
+ ]
+
+ const handleSuccess = ({ amount, note }, clear) => {
+ onGeneratePaymentRequest({ amount, note })
+ .catch(console.error)
+ showPopup(POPUP_NAME)
+ clear()
+ }
+
+ const handleError = (errors) => {
+ console.log('error', errors)
+ }
+
+ const handleClosePopup = (...args) => {
+ closePopup(...args)
+ onSuccess('Copied to Clipboard')
+ }
+
+ const styles = {
+ wrap: {
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'space-between',
+ },
+ }
+
+ return (
+
+ )
+}
+
+export default connect(
+ state => ({
+ paymentRequest: store.getPaymentRequest(state),
+ address: store.getAddress(state),
+ }), {
+ showPopup: popupActions.onOpen,
+ closePopup: popupActions.onClose,
+ onFetchAddress: actions.fetchAddress,
+ onGeneratePaymentRequest: actions.generatePaymentRequest,
+ onSuccess: notificationActions.addNotification,
+ },
+)(Pay)
+
+export { default as reducer, actions, selectors } from './reducer'
diff --git a/packages/lightning-core/request/reducer.js b/packages/lightning-core/request/reducer.js
new file mode 100644
index 000000000..1d1f65106
--- /dev/null
+++ b/packages/lightning-core/request/reducer.js
@@ -0,0 +1,60 @@
+import { GRPC } from 'redux-grpc-middleware'
+import { actions as POPUP } from 'lightning-popup'
+import { decoratePaymentRequest } from '../helpers'
+
+export const FETCH_ADDRESS_REQUEST = 'REQUEST/FETCH_ADDRESS_REQUEST'
+export const FETCH_ADDRESS = 'REQUEST/FETCH_ADDRESS'
+export const FETCH_ADDRESS_FAILURE = 'REQUEST/FETCH_ADDRESS_FAILURE'
+export const GENERATE_PAYMENT_REQUEST = 'REQUEST/GENERATE_PAYMENT_REQUEST'
+
+const initialState = {
+ paymentRequest: '',
+ address: '',
+}
+
+export default (state = initialState, action) => {
+ switch (action.type) {
+ case FETCH_ADDRESS_REQUEST:
+ return { ...state, address: 'Opening Wallet...' }
+ case FETCH_ADDRESS:
+ return { ...state, address: action.address }
+ case FETCH_ADDRESS_FAILURE:
+ return { ...state, address: 'Initializing Wallet' }
+ case POPUP.CLOSE_POPUP: {
+ if (action.name === 'paymentRequest') {
+ return { ...state, paymentRequest: '' }
+ }
+ return state
+ }
+ case GENERATE_PAYMENT_REQUEST:
+ return { ...state, paymentRequest: decoratePaymentRequest(action.paymentRequest) }
+ default: return state
+ }
+}
+
+export const actions = {
+ fetchAddress: () => ({
+ [GRPC]: {
+ method: 'newWitnessAddress',
+ types: [FETCH_ADDRESS_REQUEST, FETCH_ADDRESS, FETCH_ADDRESS_FAILURE],
+ },
+ }),
+ generatePaymentRequest: ({ amount, note }) => ({
+ [GRPC]: {
+ method: 'addInvoice',
+ body: {
+ memo: note,
+ value: amount,
+ },
+ schema: data => ({
+ paymentRequest: data.payment_request,
+ }),
+ types: GENERATE_PAYMENT_REQUEST,
+ },
+ }),
+}
+
+export const selectors = {
+ getPaymentRequest: state => state.paymentRequest,
+ getAddress: state => state.address,
+}
diff --git a/packages/lightning-core/selectors.js b/packages/lightning-core/selectors.js
new file mode 100644
index 000000000..c5b322619
--- /dev/null
+++ b/packages/lightning-core/selectors.js
@@ -0,0 +1,15 @@
+import { scopeStateToSelectors } from 'redux-selector'
+
+import { selectors as accounts } from './accounts'
+import { selectors as pay } from './pay'
+import { selectors as request } from './request'
+import { selectors as settings } from './settings'
+import { selectors as transactions } from './transactions'
+
+export const selectors = scopeStateToSelectors({
+ accounts,
+ pay,
+ request,
+ settings,
+ transactions,
+})
diff --git a/packages/lightning-core/settings/Terminal.js b/packages/lightning-core/settings/Terminal.js
new file mode 100644
index 000000000..7791e07f3
--- /dev/null
+++ b/packages/lightning-core/settings/Terminal.js
@@ -0,0 +1,41 @@
+import React, { Component } from 'react';
+import { Input } from '../common';
+import { ipcRenderer, ipcMain } from 'electron';
+import reactCSS from 'reactcss'
+
+export default class Terminal extends Component {
+ render() {
+ const styles = reactCSS({
+ 'default': {
+ changer: {
+ marginTop: 10,
+ marginBottom: 10,
+ borderLeft: '1px solid #ddd',
+ paddingLeft: 15,
+ paddingRight: 15,
+ display: 'flex',
+ alignItems: 'center',
+ color: '#999',
+ },
+ },
+ })
+
+ const handleKeyPress = (e) => {
+ if (e.key === 'Enter') {
+ ipcRenderer.send('terminal-command', e.target.value.split(' '));
+ e.target.value = '';
+ }
+
+ }
+ const changer = (
+ $ lncli
+ )
+
+ return (
+
+ )
+ }
+}
+
diff --git a/packages/lightning-core/settings/index.js b/packages/lightning-core/settings/index.js
new file mode 100644
index 000000000..4bf8b0636
--- /dev/null
+++ b/packages/lightning-core/settings/index.js
@@ -0,0 +1,107 @@
+import React from 'react'
+import _ from 'lodash'
+import reactCSS from 'reactcss'
+import { connect } from 'react-redux'
+import { store } from 'lightning-store'
+import { remote } from 'electron'
+import { Box, Text } from 'lightning-components'
+import { Head, Page } from '../common'
+import { InfiniteScroll } from '../common'
+import Terminal from './terminal'
+
+const { Menu, MenuItem } = remote
+
+const SettingsLogs = ({ logs }) => {
+ const insideStyles = {
+ padding: 15,
+ overflowX: 'scroll',
+ }
+ return (
+
+ { _.map(logs, (log, i) => {
+ return (
+
+ { log }
+
+ )
+ }) }
+
+ )
+}
+
+export const SettingsPage = ({ logs, pubkey }) => {
+ const styles = reactCSS({
+ 'default': {
+ page: {
+ padding: 30,
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ width: '90%',
+ },
+ pubkeyandlog: {
+ boxSizing: 'border-box',
+ padding: 'large',
+ direction: 'column',
+ minWidth: 0,
+ flex: 1,
+ },
+ title: {
+ size: 'medium',
+ paddingBottom: 'medium',
+ color: 'gray',
+ },
+ account: {
+ paddingBottom: 'large',
+ },
+ logs: {
+ flex: 1,
+ display: 'flex',
+ zDepth: 1,
+ width: '100%',
+ height: '70%',
+ boxSizing: 'border-box',
+ background: 'white',
+ marginBottom: 'medium',
+ overflowX: 'scroll',
+ },
+ },
+ })
+
+ const menu = new Menu()
+ menu.append(new MenuItem({ label: 'Copy', role: 'copy' }))
+ menu.append(new MenuItem({ label: 'Select All', role: 'selectall' }))
+ const handleMenu = () => menu.popup(remote.getCurrentWindow())
+
+ return (
+
+
+
+ { pubkey ? (
+
+ Pubkey: { pubkey }
+
+ ) : null }
+ lncli Access
+
+
+
+ Logs
+
+
+
+
+
+ )
+}
+
+export default connect(
+ state => ({
+ logs: store.getRecentLogs(state),
+ pubkey: store.getAccountPubkey(state),
+ }),
+)(SettingsPage)
+
+export { default as reducer, actions, selectors } from './reducer'
diff --git a/packages/lightning-core/reducers/lnd.js b/packages/lightning-core/settings/reducer.js
similarity index 89%
rename from packages/lightning-core/reducers/lnd.js
rename to packages/lightning-core/settings/reducer.js
index 747092f25..cfccf098b 100644
--- a/packages/lightning-core/reducers/lnd.js
+++ b/packages/lightning-core/settings/reducer.js
@@ -19,5 +19,5 @@ export const actions = {
}
export const selectors = {
- getRecentLogs: state => _.take(state.logs, 40),
+ getRecentLogs: state => _.takeRight(state.logs, 500),
}
diff --git a/packages/lightning-core/transactions/TransactionsList.js b/packages/lightning-core/transactions/TransactionsList.js
new file mode 100644
index 000000000..869489fe9
--- /dev/null
+++ b/packages/lightning-core/transactions/TransactionsList.js
@@ -0,0 +1,56 @@
+import React from 'react'
+import _ from 'lodash'
+import reactCSS from 'reactcss'
+
+import { Icon } from 'lightning-components'
+import { LoadingIcon } from '../common'
+import TransactionsListItem from './TransactionsListItem'
+
+export const TransactionsList = ({ transactions, loading }) => {
+ const styles = reactCSS({
+ 'default': {
+ list: {
+ borderTop: '1px solid #ddd',
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ },
+ empty: {
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ color: '#bbb',
+ userSelect: 'none',
+ cursor: 'default',
+ },
+ emptyLabel: {
+ fontSize: 24,
+ paddingTop: 10,
+ },
+ },
+ })
+ return (
+
+ { _.map(transactions, transaction => (
+
+ )) }
+
+ { loading ? (
+
+
+
+ ) : null }
+
+ { !transactions.length && !loading ? (
+
+
+
No Transactions Yet
+
+ ) : null }
+
+ )
+}
+
+export default TransactionsList
diff --git a/packages/lightning-core/transactions/TransactionsListItem.js b/packages/lightning-core/transactions/TransactionsListItem.js
new file mode 100644
index 000000000..c3f365a92
--- /dev/null
+++ b/packages/lightning-core/transactions/TransactionsListItem.js
@@ -0,0 +1,90 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+import { Text, Icon } from 'lightning-components'
+import { Money, MoneySign } from '../common'
+import { connect } from 'react-redux'
+import { withRouter } from 'react-router'
+import { actions as accountActions } from '../accounts'
+import { store } from 'lightning-store'
+
+export const TransactionsListItem = ({ type, hash, memo, currency, amount, status }) => {
+ const styles = reactCSS({
+ 'default': {
+ item: {
+ paddingTop: 20,
+ paddingBottom: 20,
+ borderBottom: '1px solid #ddd',
+ display: 'flex',
+ flexShrink: 0,
+ },
+ icon: {
+ paddingRight: 13,
+ color: '#bbb',
+ },
+ column: {
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ },
+ details: {
+ textAlign: 'right',
+ whiteSpace: 'nowrap',
+ },
+ text: {
+ flex: 1,
+ marginRight: 20,
+ },
+ big: {
+ fontSize: 16,
+ color: '#333',
+ fontWeight: 500,
+ },
+ sent: {
+ fontWeight: 400,
+ color: '#999',
+ },
+ small: {
+ marginTop: 4,
+ fontSize: 13,
+ color: '#999',
+ userSelect: 'none',
+ cursor: 'default',
+ },
+ overflow: {
+ minWidth: 330,
+ wordBreak: 'break-word',
+ },
+ },
+ })
+ return (
+
+
+
+
+
+
+ TxID: { hash }
+
+ {memo &&
Note: { memo }
}
+
+
+
+
+ )
+}
+
+export default withRouter(connect(
+ state => ({
+ serverRunning: store.getServerRunning(state),
+ isSynced: store.getSyncedToChain(state),
+ pubkey: store.getAccountPubkey(state),
+ currency: store.getCurrency(state),
+ balances: store.getAccountBalances(state),
+ }), {
+ fetchAccount: accountActions.fetchAccount,
+ fetchBalances: accountActions.fetchBalances,
+ },
+)(TransactionsListItem))
diff --git a/packages/lightning-core/transactions/index.js b/packages/lightning-core/transactions/index.js
new file mode 100644
index 000000000..0f924bea2
--- /dev/null
+++ b/packages/lightning-core/transactions/index.js
@@ -0,0 +1,36 @@
+import React from 'react'
+import { connect } from 'react-redux'
+import { store } from 'lightning-store'
+import { Head, Page } from '../common'
+import { actions } from './reducer'
+
+import TransactionsList from './TransactionsList'
+
+export class Transactions extends React.Component {
+ componentDidMount() { this.props.onFetchTransactions() }
+
+ render() {
+ const { loading, transactions } = this.props
+ return (
+
+
+
+
+ )
+ }
+}
+
+export default connect(
+ state => ({
+ loading: store.getTransactionsLoading(state),
+ transactions: store.getRecentTransactions(state),
+ }), {
+ onFetchTransactions: actions.fetchTransactions,
+ },
+)(Transactions)
+
+export { default as reducer, actions, selectors } from './reducer'
diff --git a/packages/lightning-core/transactions/reducer.js b/packages/lightning-core/transactions/reducer.js
new file mode 100644
index 000000000..9c96e8c31
--- /dev/null
+++ b/packages/lightning-core/transactions/reducer.js
@@ -0,0 +1,109 @@
+import _ from 'lodash'
+import { GRPC } from 'redux-grpc-middleware'
+import { toHash } from '../helpers'
+
+export const REQUEST = 'TRANSACTIONS/REQUEST'
+export const REQUEST_ERROR = 'TRANSACTIONS/REQUEST_ERROR'
+export const GET_TRANSACTIONS = 'TRANSACTIONS/GET_TRANSACTIONS'
+export const LIST_INVOICES = 'TRANSACTIONS/LIST_INVOICES'
+export const LIST_PAYMENTS = 'TRANSACTIONS/LIST_PAYMENTS'
+
+const initialState = {
+ loading: false,
+}
+
+export default (state = initialState, action) => {
+ switch (action.type) {
+ case REQUEST:
+ return { ...state, loading: true }
+ case GET_TRANSACTIONS:
+ case LIST_INVOICES:
+ case LIST_PAYMENTS:
+ return {
+ ...state,
+ loading: false,
+ list: _.reduce(action.transactions, (all, transaction) => {
+ // eslint-disable-next-line no-param-reassign
+ all[transaction.id] = transaction
+ return all
+ }, { ...state.list }),
+ }
+ case REQUEST_ERROR:
+ return { ...state, loading: false, list: [] }
+ default: return state
+ }
+}
+
+export const actions = {
+ fetchTransactions: () => (dispatch) => {
+ dispatch({
+ [GRPC]: {
+ method: 'getTransactions',
+ types: [REQUEST, GET_TRANSACTIONS, REQUEST_ERROR],
+ schema: data => ({
+ transactions: _.map(data.transactions, transaction => ({
+ id: transaction.tx_hash,
+ type: 'bitcoin',
+ amount: transaction.amount,
+ status: transaction.num_confirmations < 1 ? 'unconfirmed' : 'confirmed',
+ date: new Date(parseInt(transaction.time_stamp, 10)),
+ hash: transaction.tx_hash,
+ })),
+ }),
+ },
+ })
+ .catch(() => {})
+ dispatch({
+ [GRPC]: {
+ method: 'listInvoices',
+ types: [REQUEST, LIST_INVOICES, REQUEST_ERROR],
+ schema: data => ({
+ transactions: _.map(data.invoices, invoice => ({
+ id: invoice.creation_date,
+ type: 'lightning',
+ amount: invoice.value,
+ status: invoice.settled ? 'complete' : 'in-progress',
+ date: new Date(parseInt(invoice.creation_date, 10)),
+ memo: invoice.memo,
+ hash: toHash(invoice.r_preimage),
+ })),
+ }),
+ },
+ })
+ .catch(() => {})
+ dispatch({
+ [GRPC]: {
+ method: 'listPayments',
+ types: [null, LIST_PAYMENTS, REQUEST_ERROR],
+ schema: data => ({
+ transactions: _.map(data.payments, payment => ({
+ id: payment.creation_date,
+ type: 'lightning',
+ amount: payment.value,
+ status: 'complete',
+ date: new Date(parseInt(payment.creation_date, 10)),
+ hash: payment.payment_hash,
+ })),
+ }),
+ },
+ })
+ .catch(() => {})
+ },
+ subscribeTransactions: () => ({
+ [GRPC]: {
+ method: 'subscribeTransactions',
+ stream: true,
+ },
+ }),
+ subscribeInvoices: () => ({
+ [GRPC]: {
+ method: 'subscribeInvoices',
+ stream: true,
+ },
+ }),
+}
+
+export const selectors = {
+ getRecentTransactions: state => _.orderBy(state.list, 'date', 'desc'),
+ getTransactionsLoading: state => state.loading,
+}
diff --git a/packages/lightning-currency/currencies.js b/packages/lightning-currency/currencies.js
new file mode 100644
index 000000000..487202c02
--- /dev/null
+++ b/packages/lightning-currency/currencies.js
@@ -0,0 +1,49 @@
+import _ from 'lodash'
+import { addCommas, removeCommas } from './helper'
+
+const toBTC = (sat) => {
+ return removeCommas(sat) / 100000000
+}
+
+const currencies = {
+ sat: {
+ sign: 'SAT',
+ value: 'SAT',
+ format: (sat) => {
+ const number = removeCommas(sat).toFixed(0)
+ return addCommas(number)
+ },
+ },
+ btc: {
+ sign: '฿',
+ value: 'BTC',
+ format: (sat) => {
+ const number = toBTC(sat).toFixed(4)
+ const split = number.split('.')
+ return `${ addCommas(split[0]) }.${ split[1] }`
+ },
+ },
+ usd: {
+ sign: '$',
+ value: 'USD',
+ format: (sat) => {
+ return addCommas((toBTC(sat) * 1194.99).toFixed(2))
+ },
+ },
+ eur: {
+ sign: '€',
+ value: 'EUR',
+ format: (sat) => {
+ return addCommas((toBTC(sat) * 1131.87).toFixed(2))
+ },
+ },
+}
+
+const missing = {
+ sign: '?',
+ value: 'N/A',
+ format: () => 'MISSING',
+}
+
+export const getCurrency = id => currencies[id] || missing
+export const getCurrencyValues = _.mapValues(currencies, 'code')
diff --git a/packages/lightning-currency/helper.js b/packages/lightning-currency/helper.js
new file mode 100644
index 000000000..8571a2e30
--- /dev/null
+++ b/packages/lightning-currency/helper.js
@@ -0,0 +1,9 @@
+import _ from 'lodash'
+
+export const addCommas = (number) => {
+ return number.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,')
+}
+
+export const removeCommas = (string = 0) => {
+ return _.isString(string) ? Number(string.replace(/[^0-9]/g, '')) : string
+}
diff --git a/packages/lightning-currency/index.js b/packages/lightning-currency/index.js
new file mode 100644
index 000000000..cd29d10b1
--- /dev/null
+++ b/packages/lightning-currency/index.js
@@ -0,0 +1,3 @@
+export * from './currencies'
+
+export { default as reducer, actions, selectors } from './reducer'
diff --git a/packages/lightning-currency/package.json b/packages/lightning-currency/package.json
new file mode 100644
index 000000000..a16736236
--- /dev/null
+++ b/packages/lightning-currency/package.json
@@ -0,0 +1,19 @@
+{
+ "version": "0.1.0",
+ "name": "lightning-currency",
+ "main": "index.js",
+ "scripts": {
+ "start": "node index.js"
+ },
+ "author": "case ",
+ "license": "MIT",
+ "dependencies": {
+ "lightning-components": "^0.1.1",
+ "lightning-store": "^0.1.1",
+ "lodash": "^4.17.2",
+ "react": "^15.4.1",
+ "react-redux": "^4.4.6",
+ "reactcss": "^1.1.1",
+ "redux": "^3.6.0"
+ }
+}
diff --git a/packages/lightning-currency/reducer.js b/packages/lightning-currency/reducer.js
new file mode 100644
index 000000000..449ced532
--- /dev/null
+++ b/packages/lightning-currency/reducer.js
@@ -0,0 +1,8 @@
+export default (state = {}, action) => {
+ switch (action.type) {
+ default: return state
+ }
+}
+
+export const actions = { }
+export const selectors = { }
diff --git a/packages/lightning-electron/app.html b/packages/lightning-electron/app.html
deleted file mode 100644
index f654d3464..000000000
--- a/packages/lightning-electron/app.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-Lightning
-
-
-
-
-
-
-
-
-
diff --git a/packages/lightning-electron/main.development.js b/packages/lightning-electron/main.development.js
deleted file mode 100644
index 2cd479cd7..000000000
--- a/packages/lightning-electron/main.development.js
+++ /dev/null
@@ -1,126 +0,0 @@
-/* eslint-disable global-require, no-console */
-
-import { app, BrowserWindow } from 'electron'
-import windowStateKeeper from 'electron-window-state'
-import _ from 'lodash'
-import observe from 'observe'
-import cp from 'child_process'
-import ps from 'ps-node'
-import './lnd'
-
-let mainWindow = null
-
-const isProcessRunning = command => new Promise((resolve, reject) => {
- ps.lookup({ command },
- (err, resultList) => {
- if (err) { throw new Error(err) }
- resultList[0] ? resolve(resultList[0]) : reject()
- }
- )
-})
-
-const runProcesses = (processes, logs) => {
- _.map(processes, (process) => {
- isProcessRunning(process.name)
- .then((p) => {
- console.log(`${ process.name } Already Running`, p)
- })
- .catch(() => {
- const prefix = `${ process.name }: `
- const instance = cp.execFile(process.name, process.args, { cwd: './bin' }, (error) => {
- if (error) { logs.push(`${ error.code }: ${ error.errno }`); return }
- })
- instance.stdout.on('data', data => logs.push(prefix + data))
- instance.stderr.on('data', data => logs.push(prefix + data))
- })
- })
-}
-
-const logBuffer = []
-const logs = observe(logBuffer)
-
-const processes = [
- {
- name: 'lnd',
- args: [
- '--btcdhost=127.0.0.1',
- '--rpcuser=kek',
- '--rpcpass=kek',
- '--simnet',
- '--debuglevel=trace',
- '--debughtlc',
- ],
- }, {
- name: 'btcd',
- args: [
- '--rpcuser=kek',
- '--rpcpass=kek',
- '--simnet',
- '--miningaddr=4NyWssGkW6Nbwj3nXrJU54U2ijHgWaKZ1N19w',
- ],
- },
-]
-
-runProcesses(processes, logs)
-
-const createWindow = () => {
- const mainWindowState = windowStateKeeper({
- defaultWidth: 750,
- defaultHeight: 500,
- })
-
- const { x, y, width, height } = mainWindowState
- mainWindow = new BrowserWindow({
- x,
- y,
- width,
- height,
- show: false,
- transparent: true,
- frame: false,
- title: 'Lightning',
- })
-
- mainWindowState.manage(mainWindow)
- mainWindow.loadURL(`file://${ __dirname }/app/app.html`)
-
- mainWindow.webContents.on('did-finish-load', () => {
- mainWindow.show()
- mainWindow.focus()
-
- mainWindow.webContents.send('logs', logBuffer)
- })
-
- logs.on('change', (change) => {
- const log = logBuffer[change.index]
- mainWindow && mainWindow.webContents.send('log', log)
- })
-
- if (process.env.NODE_ENV === 'development') {
- mainWindow.openDevTools()
- }
-
- mainWindow.on('closed', () => {
- mainWindow = null
- })
-}
-
-if (process.env.NODE_ENV === 'development') {
- require('electron-debug')()
-}
-
-app.on('window-all-closed', () => {
- if (process.platform !== 'darwin') app.quit()
-})
-
-// if (process.platform === 'darwin') {
-// const template = [
-// {
-// label: app.getName(),
-// },
-// ]
-// const menu = Menu.buildFromTemplate(template)
-// Menu.setApplicationMenu(menu)
-// }
-
-app.on('ready', createWindow)
diff --git a/packages/lightning-electron/package.js b/packages/lightning-electron/package.js
deleted file mode 100644
index 039b3779a..000000000
--- a/packages/lightning-electron/package.js
+++ /dev/null
@@ -1,157 +0,0 @@
-/* eslint-disable no-console, consistent-return */
-/* eslint generator-star-spacing: 0 */
-
-import 'babel-polyfill'
-import os from 'os'
-import webpack from 'webpack'
-import packager from 'electron-packager'
-import del from 'del'
-import minimist from 'minimist'
-import { exec } from 'child_process'
-import cfg from './webpack.config.production'
-import pkg from './package.json'
-
-import electronCfg from './webpack.config.electron'
-
-
-/**
- * First two values are node path and current script path
- * https://nodejs.org/docs/latest/api/process.html#process_process_argv
- */
-const argv = minimist(process.argv.slice(2))
-
-/**
- * Do not package node modules from 'devDependencies'
- * and 'dependencies' that are set as external
- */
-const toNodePath = name => `/node_modules/${ name }($|/)`
-const devDeps = Object
- .keys(pkg.devDependencies)
- .map(toNodePath)
-
-const depsExternal = Object
- .keys(pkg.dependencies)
- .filter(name => !electronCfg.externals.includes(name))
- .map(toNodePath)
-
-
-const appName = argv.name || argv.n || pkg.productName
-const shouldUseAsar = argv.asar || argv.a || false
-const shouldBuildAll = argv.all || false
-
-
-const DEFAULT_OPTS = {
- dir: './',
- name: appName,
- asar: shouldUseAsar,
- ignore: [
- '^/test($|/)',
- '^/release($|/)',
- '^/main.development.js',
- ]
- .concat(devDeps)
- .concat(depsExternal),
-}
-
-const icon = argv.icon || argv.i || 'app/app'
-if (icon) DEFAULT_OPTS.icon = icon
-
-
-/**
- * @desc Execute the webpack build process on given config object
- * @param {Object} cfg
- * @return {Promise}
- */
-function build(config) {
- return new Promise((resolve, reject) => {
- webpack(config, (err, stats) => {
- if (err) return reject(err)
- resolve(stats)
- })
- })
-}
-
-function pack(plat, arch, cb) {
- // there is no darwin ia32 electron
- if (plat === 'darwin' && arch === 'ia32') return
-
- const iconObj = {
- icon: DEFAULT_OPTS.icon + (() => {
- let extension = '.png'
- if (plat === 'darwin') extension = '.icns'
- if (plat === 'win32') extension = '.ico'
-
- return extension
- })(),
- }
-
- const opts = Object.assign({}, DEFAULT_OPTS, iconObj, {
- 'platform': plat,
- arch,
- 'prune': true,
- 'app-version': pkg.version || DEFAULT_OPTS.version,
- 'out': `release/${ plat }-${ arch }`,
- })
-
- packager(opts, cb)
-}
-
-
-function log(plat, arch) {
- return (err, filepath) => {
- if (err) return console.error(err, filepath)
- console.log(`${ plat }-${ arch } finished!`)
- }
-}
-
-
-/** @desc Build, clear previous releases and pack new versions */
-async function startPack() {
- console.log('start pack...')
-
- try {
- /**
- * - Build the 'Main process' and 'Renderer Process' files.
- * - Clear the ./release directory
- */
- await build(electronCfg)
- await build(cfg)
- await del('release')
-
- // Start the packing process
- if (shouldBuildAll) {
- // build for all platforms
- const archs = ['ia32', 'x64']
- const platforms = ['linux', 'win32', 'darwin']
-
- platforms.forEach((plat) => {
- archs.forEach((arch) => {
- pack(plat, arch, log(plat, arch))
- })
- })
- } else {
- // build for current platform only
- pack(os.platform(), os.arch(), log(os.platform(), os.arch()))
- }
- } catch (error) {
- console.error(error)
- }
-}
-
-
-const version = argv.version || argv.v
-if (version) {
- DEFAULT_OPTS.version = version
- startPack()
-} else {
- // use the same version as the currently-installed electron-prebuilt
- exec('npm list electron --dev', (err, stdout) => {
- if (err) {
- DEFAULT_OPTS.version = '1.2.0'
- } else {
- DEFAULT_OPTS.version = stdout.split('electron@')[1].replace(/\s/g, '')
- }
-
- startPack()
- })
-}
diff --git a/packages/lightning-electron/package.json b/packages/lightning-electron/package.json
deleted file mode 100644
index 2aea7e83e..000000000
--- a/packages/lightning-electron/package.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "lightning-electron",
- "version": "0.1.0",
- "description": "",
- "main": "main.development.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "author": "case ",
- "license": "MIT",
- "dependencies": {
- "electron": "^1.4.12",
- "electron-debug": "^1.1.0",
- "electron-window-state": "^4.0.1",
- "lodash": "^4.17.2",
- "observe": "^1.3.7",
- "ps-node": "^0.1.4"
- }
-}
diff --git a/packages/lightning-forms/components/Field.js b/packages/lightning-forms/components/Field.js
new file mode 100644
index 000000000..ba0bbcef7
--- /dev/null
+++ b/packages/lightning-forms/components/Field.js
@@ -0,0 +1,59 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+
+export const Field = ({ name, type, placeholder, value, component, onChange,
+ disabled, errorText, error }) => {
+ const styles = reactCSS({
+ 'default': {
+ field: {
+ display: 'flex',
+ },
+ error: {
+ display: 'flex',
+ alignItems: 'center',
+ paddingLeft: 20,
+ fontSize: 14,
+ color: 'rgba(213, 61, 80, 1)',
+ },
+ },
+ })
+
+ const handleChange = e =>
+ (component ? onChange(e) : onChange({ [e.target.name]: e.target.value }))
+
+ const Component = component || 'input'
+
+ return (
+
+
+ { errorText ?
{ errorText }
: null }
+
+ )
+}
+
+Field.defaultProps = {
+ type: 'text',
+ value: '',
+}
+
+Field.propTypes = {
+ name: React.PropTypes.string.isRequired,
+ type: React.PropTypes.string,
+ placeholder: React.PropTypes.string,
+ value: React.PropTypes.string,
+ // component: React.PropTypes.element,
+ // required: React.PropTypes.bool,
+ // requiredMessage: React.PropTypes.string,
+ // validate: React.PropTypes.func,
+}
+
+export default Field
diff --git a/packages/lightning-forms/components/Form.js b/packages/lightning-forms/components/Form.js
new file mode 100644
index 000000000..06ca03f4b
--- /dev/null
+++ b/packages/lightning-forms/components/Form.js
@@ -0,0 +1,158 @@
+/* eslint-disable react/forbid-prop-types */
+
+import React from 'react'
+import _ from 'lodash'
+import reactCSS from 'reactcss'
+import { connect } from 'react-redux'
+import { actions, selectors } from '../reducer'
+
+import Field from './Field'
+
+const validate = fields => new Promise((resolve, reject) => {
+ const errors = {}
+ _.map(fields, (field) => {
+ if (field.required && field.value === '') {
+ errors[field.name] = { error: true, errorText: `${ field.name } is empty` }
+ }
+ })
+
+ const values = _.reduce(fields, (all, field) => {
+ // eslint-disable-next-line no-param-reassign
+ all[field.name] = field.value
+ return all
+ }, {})
+
+ _.isEmpty(errors) ? resolve(values) : reject(errors)
+})
+
+class Form extends React.Component {
+ componentDidMount() {
+ const { name, fields, initForm } = this.props
+ const data = _.reduce(fields, (all, field) => {
+ // eslint-disable-next-line no-param-reassign
+ all[field.name] = field.value || ''
+ return all
+ }, {})
+ initForm(name, data)
+ }
+
+ render() {
+ const { submitLabel, clearLabel, name, combinedFields, spacing,
+ onError, onSuccess, editForm, clearForm, setFormErrors, onChange } = this.props
+
+ const wasEdited = _.some(combinedFields, 'value')
+ const canSubmit = _(combinedFields).filter('required').every('value')
+
+ const styles = reactCSS({
+ 'default': {
+ form: {
+ userSelect: 'none',
+ cursor: 'default',
+ },
+ field: {
+ paddingBottom: spacing,
+ },
+ controls: {
+ display: 'flex',
+ alignItems: 'stretch',
+ height: 54,
+ },
+ button: {
+ display: 'flex',
+ alignItems: 'center',
+ paddingLeft: 20,
+ paddingRight: 20,
+ fontSize: 16,
+ },
+ submit: {
+ backgroundColor: '#ddd',
+ borderRadius: 2,
+ color: '#fff',
+
+ transition: 'background-color 100ms ease-out',
+ },
+ clear: {
+ color: '#999',
+ cursor: 'pointer',
+ },
+ },
+ 'canSubmit': {
+ submit: {
+ cursor: 'pointer',
+ backgroundColor: '#4990E2',
+ boxShadow: '0 2px 4px rgba(89, 217, 164, 0.3)',
+ },
+ },
+ }, { canSubmit })
+
+ const handleSubmit = () => {
+ validate(combinedFields)
+ .then((values) => {
+ const clear = () => clearForm(name)
+ onSuccess(values, clear)
+ })
+ .catch((errors) => {
+ setFormErrors(name, errors)
+ onError(errors)
+ })
+ }
+
+ const handleClear = () => clearForm(name)
+
+ const handleFieldChange = (change) => {
+ onChange && onChange(change)
+ editForm(name, change)
+ }
+
+ return (
+
+
+ { _.map(combinedFields, field => (
+
+
+
+ ))}
+
+
+
+ { submitLabel }
+
+ { wasEdited ? (
+
+ { clearLabel }
+
+ ) : null }
+
+
+ )
+ }
+}
+
+Form.defaultProps = {
+ submitLabel: 'Submit',
+ clearLabel: 'Clear',
+ onSuccess: () => {},
+ onError: () => {},
+ spacing: 20,
+}
+
+Form.propTypes = {
+ name: React.PropTypes.string.isRequired,
+ fields: React.PropTypes.array.isRequired,
+}
+
+export default connect(
+ (state, ownProps) => {
+ const values = selectors.getFormFields(state.forms, ownProps.name)
+ const errors = selectors.getFormErrors(state.forms, ownProps.name)
+ return {
+ combinedFields: _.map(ownProps.fields, (field) => {
+ return { ...field, ...errors[field.name], value: values[field.name] }
+ }),
+ }
+ },
+ actions,
+)(Form)
diff --git a/packages/lightning-forms/index.js b/packages/lightning-forms/index.js
new file mode 100644
index 000000000..b5a5b9483
--- /dev/null
+++ b/packages/lightning-forms/index.js
@@ -0,0 +1,3 @@
+export { default as Form } from './components/Form'
+
+export { reducer, actions, selectors } from './reducer'
diff --git a/packages/lightning-forms/package.json b/packages/lightning-forms/package.json
new file mode 100644
index 000000000..fa79b0fa7
--- /dev/null
+++ b/packages/lightning-forms/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "lightning-forms",
+ "version": "0.1.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "lodash": "^4.16.2",
+ "react": "^15.4.2",
+ "react-redux": "^4.4.6",
+ "reactcss": "^1.1.1",
+ "redux": "^3.6.0"
+ }
+}
diff --git a/packages/lightning-forms/reducer.js b/packages/lightning-forms/reducer.js
new file mode 100644
index 000000000..48f75ef40
--- /dev/null
+++ b/packages/lightning-forms/reducer.js
@@ -0,0 +1,43 @@
+import _ from 'lodash'
+
+export const INIT_FORM = 'LIGHTNING_FORMS/INIT_FORM'
+export const EDIT_FORM = 'LIGHTNING_FORMS/EDIT_FORM'
+export const CLEAR_FORM = 'LIGHTNING_FORMS/CLEAR_FORM'
+export const SET_FORM_ERRORS = 'LIGHTNING_FORMS/SET_FORM_ERRORS'
+
+const formReducer = (state = {}, action) => {
+ switch (action.type) {
+ case INIT_FORM:
+ case EDIT_FORM:
+ return { ...state, fields: { ...state.fields, ...action.form.data } }
+ case CLEAR_FORM:
+ return { ...state, fields: _.mapValues(state.fields, () => ''), errors: {} }
+ case SET_FORM_ERRORS:
+ return { ...state, errors: action.errors }
+ default: return state
+ }
+}
+
+export const reducer = (state = {}, action) => {
+ switch (action.type) {
+ case INIT_FORM:
+ case EDIT_FORM:
+ case CLEAR_FORM:
+ case SET_FORM_ERRORS:
+ return { ...state, [action.form.name]: formReducer(state[action.form.name], action) }
+ default: return state
+ }
+}
+
+export const actions = {
+ initForm: (name, data) => ({ type: INIT_FORM, form: { name, data } }),
+ editForm: (name, data) => ({ type: EDIT_FORM, form: { name, data } }),
+ clearForm: name => ({ type: CLEAR_FORM, form: { name } }),
+ setFormErrors: (name, errors) => ({ type: SET_FORM_ERRORS, form: { name }, errors }),
+}
+
+export const selectors = {
+ getForm: (state, name) => state[name] || {},
+ getFormFields: (state, name) => (state[name] && state[name].fields) || {},
+ getFormErrors: (state, name) => (state[name] && state[name].errors) || {},
+}
diff --git a/packages/lightning-notifications/helpers.js b/packages/lightning-notifications/helpers.js
new file mode 100644
index 000000000..18864983e
--- /dev/null
+++ b/packages/lightning-notifications/helpers.js
@@ -0,0 +1,8 @@
+export const guid = () => {
+ const s4 = () =>
+ Math.floor((1 + Math.random()) * 0x10000)
+ .toString(16)
+ .substring(1)
+
+ return `${ s4() + s4() }-${ s4() }-${ s4() }-${ s4() }-${ s4() }${ s4() }${ s4() }`
+}
diff --git a/packages/lightning-notifications/index.js b/packages/lightning-notifications/index.js
index 10a8d26e3..be0479924 100644
--- a/packages/lightning-notifications/index.js
+++ b/packages/lightning-notifications/index.js
@@ -1,4 +1,5 @@
import _ from 'lodash'
+import { guid } from './helpers'
export { default as Notifications } from './Notifications'
@@ -6,15 +7,6 @@ export const ADD = 'NOTIFICATIONS/ADD'
export const REMOVE = 'NOTIFICATIONS/REMOVE'
export const NOTIFICATION = 'NOTIFICATIONS/NOTIFICATION'
-function guid() {
- function s4() {
- return Math.floor((1 + Math.random()) * 0x10000)
- .toString(16)
- .substring(1)
- }
- return `${ s4() + s4() }-${ s4() }-${ s4() }-${ s4() }-${ s4() }${ s4() }${ s4() }`
-}
-
export default function notifications(state = [], action) {
const data = {
[ADD]: () => {
diff --git a/packages/lightning-notifications/package.json b/packages/lightning-notifications/package.json
index 544a58b4f..756a395a3 100644
--- a/packages/lightning-notifications/package.json
+++ b/packages/lightning-notifications/package.json
@@ -1,6 +1,6 @@
{
"name": "lightning-notifications",
- "version": "0.1.0",
+ "version": "0.1.1",
"description": "",
"main": "index.js",
"scripts": {
@@ -9,11 +9,12 @@
"author": "case ",
"license": "MIT",
"dependencies": {
- "lightning-components": "^0.1.0",
- "lightning-store": "^0.1.0",
+ "lightning-components": "^0.1.1",
+ "lightning-store": "^0.1.1",
"lodash": "^4.17.2",
"react": "^15.4.1",
- "react-redux": "^5.0.1",
- "reactcss": "^1.1.1"
+ "react-redux": "^4.4.6",
+ "reactcss": "^1.1.1",
+ "redux": "^3.6.0"
}
}
diff --git a/packages/lightning-popup/Popup.js b/packages/lightning-popup/Popup.js
new file mode 100644
index 000000000..84bc9b98c
--- /dev/null
+++ b/packages/lightning-popup/Popup.js
@@ -0,0 +1,51 @@
+import React from 'react'
+import reactCSS from 'reactcss'
+import { connect } from 'react-redux'
+import { store } from 'lightning-store'
+import { actions } from './reducer'
+
+export const Popup = ({ children, visible, onClose, name }) => {
+ const styles = reactCSS({
+ 'default': {
+ wrap: {
+ position: 'absolute',
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0,
+ },
+ cover: {
+ position: 'absolute',
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0,
+ background: 'rgba(39, 36, 41, 0.7)',
+ },
+ box: {
+ position: 'absolute',
+ left: '50%',
+ top: '50%',
+ transform: 'translate(-50%, -50%)',
+ },
+ },
+ })
+
+ const handleClose = () => onClose(name)
+
+ return visible ? (
+
+ ) : null
+}
+
+export default connect(
+ (state, ownProps) => ({
+ visible: store.getPopupVisibility(state, ownProps.name),
+ }),
+ actions,
+)(Popup)
diff --git a/packages/lightning-popup/index.js b/packages/lightning-popup/index.js
new file mode 100644
index 000000000..b269cb89d
--- /dev/null
+++ b/packages/lightning-popup/index.js
@@ -0,0 +1,2 @@
+export { default as Popup } from './Popup'
+export { reducer, actions, selectors } from './reducer'
diff --git a/packages/lightning-popup/package.json b/packages/lightning-popup/package.json
new file mode 100644
index 000000000..d2ee64d8a
--- /dev/null
+++ b/packages/lightning-popup/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "lightning-popup",
+ "version": "0.1.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "lightning-components": "^0.1.1",
+ "lightning-store": "^0.1.1",
+ "lodash": "^4.17.2",
+ "react": "^15.4.1",
+ "react-redux": "^4.4.6",
+ "reactcss": "^1.1.1",
+ "redux": "^3.6.0"
+ }
+}
diff --git a/packages/lightning-popup/reducer.js b/packages/lightning-popup/reducer.js
new file mode 100644
index 000000000..14a641118
--- /dev/null
+++ b/packages/lightning-popup/reducer.js
@@ -0,0 +1,21 @@
+export const OPEN_POPUP = 'LIGHTNING_POPUP/OPEN_POPUP'
+export const CLOSE_POPUP = 'LIGHTNING_POPUP/CLOSE_POPUP'
+
+export const reducer = (state = {}, action) => {
+ switch (action.type) {
+ case OPEN_POPUP:
+ return { ...state, [action.name]: true }
+ case CLOSE_POPUP:
+ return { ...state, [action.name]: false }
+ default: return state
+ }
+}
+
+export const actions = {
+ onClose: name => ({ type: CLOSE_POPUP, name }),
+ onOpen: name => ({ type: OPEN_POPUP, name }),
+}
+
+export const selectors = {
+ getPopupVisibility: (state, name) => state[name] || false,
+}
diff --git a/packages/lightning-store/index.js b/packages/lightning-store/index.js
index 9afc3a10a..fda20939e 100644
--- a/packages/lightning-store/index.js
+++ b/packages/lightning-store/index.js
@@ -1,17 +1,13 @@
/* eslint-disable import/no-named-as-default-member */
import { createStore } from 'redux'
-import storage from './local-storage'
-import middleware from './middleware'
+import middleware, { history } from './middleware'
import reducers from './reducers'
-const state = { ...storage.load(), transactions: [] }
-
-export function configureStore(initialState = state) {
- const store = createStore(reducers, initialState, middleware)
- storage.save(store)
-
- return store
+export function configureStore(initialState = {}) {
+ return createStore(reducers, initialState, middleware)
}
+export { history }
+
export { default as store } from './selectors'
diff --git a/packages/lightning-store/local-storage.js b/packages/lightning-store/local-storage.js
deleted file mode 100644
index c5f92c5d2..000000000
--- a/packages/lightning-store/local-storage.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import _ from 'lodash'
-
-const STATE = 'LIGHTNING_STATE'
-
-export const save = (store) => {
- // const saveState = _.debounce(() => {
- // localStorage.setItem(STATE, JSON.stringify(store.getState()))
- // }, 5000)
-
- // store.subscribe(saveState)
-}
-
-export const load = () => {
- return JSON.parse(localStorage.getItem(STATE)) || {}
-}
-
-export default exports
diff --git a/packages/lightning-store/middleware.js b/packages/lightning-store/middleware.js
index 3664bf835..6472bce8b 100644
--- a/packages/lightning-store/middleware.js
+++ b/packages/lightning-store/middleware.js
@@ -1,17 +1,19 @@
import { applyMiddleware } from 'redux'
-import { hashHistory } from 'react-router'
import { routerMiddleware } from 'react-router-redux'
import thunk from 'redux-thunk'
import createLogger from 'redux-logger'
import createIpc from 'redux-electron-ipc'
-import createGrpc from 'redux-grpc-middlware'
-import { actions as logActions } from 'lightning-core/src/reducers/lnd'
+import createGrpc from 'redux-grpc-middleware'
+import { actions as logActions } from 'lightning-core/settings'
+
+import { createHashHistory } from 'history'
const ipc = createIpc(logActions)
-const grpc = createGrpc({ path: './lnd' })
+const grpc = createGrpc()
const logger = createLogger({ level: 'info', collapsed: true })
-const router = routerMiddleware(hashHistory)
+export const history = createHashHistory()
+const router = routerMiddleware(history)
export default applyMiddleware(
grpc,
diff --git a/packages/lightning-store/package.json b/packages/lightning-store/package.json
index f40811bb6..afe83717a 100644
--- a/packages/lightning-store/package.json
+++ b/packages/lightning-store/package.json
@@ -1,6 +1,6 @@
{
"name": "lightning-store",
- "version": "0.1.0",
+ "version": "0.1.1",
"description": "",
"main": "index.js",
"scripts": {
@@ -9,12 +9,18 @@
"author": "case ",
"license": "MIT",
"dependencies": {
+ "history": "^4.6.1",
+ "lightning-core": "^1.9.1",
+ "lightning-forms": "^0.1.0",
+ "lightning-notifications": "^0.1.1",
+ "lightning-popup": "^0.1.0",
"lodash": "^4.17.2",
- "react-router": "^3.0.0",
- "react-router-redux": "^4.0.7",
+ "react": "^15.4.1",
+ "react-router-dom": "^4.0.0",
+ "react-router-redux": "^5.0.0-alpha.6",
"redux": "^3.6.0",
"redux-electron-ipc": "^1.1.3",
- "redux-grpc-middleware": "^0.1.0",
+ "redux-grpc-middleware": "^0.1.1",
"redux-logger": "^2.7.4",
"redux-selector": "^0.1.0",
"redux-thunk": "^2.1.0"
diff --git a/packages/lightning-store/reducers.js b/packages/lightning-store/reducers.js
index 6672e992f..fc95db77b 100644
--- a/packages/lightning-store/reducers.js
+++ b/packages/lightning-store/reducers.js
@@ -1,23 +1,15 @@
import { combineReducers } from 'redux'
-import { routerReducer as routing } from 'react-router-redux'
-
-import channels from 'lightning-core/src/reducers/channels'
-import lnd from 'lightning-core/src/reducers/lnd'
-import payment from 'lightning-core/src/reducers/payment'
-import transactions from 'lightning-core/src/reducers/transactions'
-import ui from 'lightning-core/src/reducers/ui'
-import wallets from 'lightning-core/src/reducers/wallets'
+import { routerReducer as router } from 'react-router-redux'
+import { reducer as core } from 'lightning-core'
+import { reducer as forms } from 'lightning-forms'
import notifications from 'lightning-notifications'
+import { reducer as popup } from 'lightning-popup'
export default combineReducers({
- channels,
- lnd,
- payment,
- transactions,
- ui,
- wallets,
-
+ router,
+ core,
+ forms,
notifications,
- routing,
+ popup,
})
diff --git a/packages/lightning-store/selectors.js b/packages/lightning-store/selectors.js
index f6dacb54e..8eb310fc0 100644
--- a/packages/lightning-store/selectors.js
+++ b/packages/lightning-store/selectors.js
@@ -1,21 +1,13 @@
import { scopeStateToSelectors } from 'redux-selector'
-import { selectors as channels } from 'lightning-core/src/reducers/channels'
-import { selectors as lnd } from 'lightning-core/src/reducers/lnd'
-import { selectors as payment } from 'lightning-core/src/reducers/payment'
-import { selectors as transactions } from 'lightning-core/src/reducers/transactions'
-import { selectors as ui } from 'lightning-core/src/reducers/ui'
-import { selectors as wallets } from 'lightning-core/src/reducers/wallets'
+import { selectors as core } from 'lightning-core'
+import { selectors as forms } from 'lightning-forms'
import { selectors as notifications } from 'lightning-notifications'
+import { selectors as popup } from 'lightning-popup'
-export default {
- ...scopeStateToSelectors({
- wallets,
- ui,
- payment,
- transactions,
- lnd,
- channels,
- notifications,
- }),
-}
+export default scopeStateToSelectors({
+ core,
+ forms,
+ notifications,
+ popup,
+})
diff --git a/packages/lightning-webpack/package.json b/packages/lightning-webpack/package.json
deleted file mode 100644
index 5d6a0c387..000000000
--- a/packages/lightning-webpack/package.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "lightning-webpack",
- "version": "0.1.0",
- "description": "",
- "main": "server.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1",
- "start": "node server.js"
- },
- "author": "case ",
- "license": "MIT",
- "dependencies": {
- "babel-register": "^6.18.0",
- "express": "^4.14.0",
- "extract-text-webpack-plugin": "^1.0.1",
- "webpack": "^1.14.0",
- "webpack-dev-middleware": "^1.9.0",
- "webpack-hot-middleware": "^2.13.2",
- "webpack-merge": "^1.1.2",
- "webpack-validator": "^2.3.0"
- }
-}
diff --git a/packages/lightning-webpack/webpack.config.eslint.js b/packages/lightning-webpack/webpack.config.eslint.js
deleted file mode 100644
index 52dadf45c..000000000
--- a/packages/lightning-webpack/webpack.config.eslint.js
+++ /dev/null
@@ -1,3 +0,0 @@
-require('babel-register')
-
-module.exports = require('./webpack.config.development')
diff --git a/packages/redux-grpc-middleware/index.js b/packages/redux-grpc-middleware/index.js
index 985d5c447..f47242023 100644
--- a/packages/redux-grpc-middleware/index.js
+++ b/packages/redux-grpc-middleware/index.js
@@ -1,38 +1,108 @@
-import electron from 'electron'
+/* eslint-disable no-console */
+
+import _ from 'lodash'
+import { remote } from 'electron'
const defaults = {
- path: './main.development.js',
+ global: {
+ connection: 'connection',
+ metadata: 'metadata',
+ serverReady: 'serverReady',
+ },
selector: 'default',
}
export const GRPC = 'GRPC/API'
+export const SERVER_STARTING = 'GRPC/SERVER_STARTING'
+export const SERVER_RUNNING = 'GRPC/SERVER_RUNNING'
export default (opts = {}) => {
const options = { ...defaults, ...opts }
- const client = electron.remote.require(options.path)[options.selector]
+ const serverReady = remote.getGlobal(options.global.serverReady)
+ const metadata = remote.getGlobal(options.global.metadata)
+
+ let client
+ let ready = false
+ let serverStartingActionSent = false
+ let serverRunningActionSent = false
+
+ serverReady && serverReady(() => (ready = true))
+
+ try {
+ client = remote.getGlobal(options.global.connection)
+ } catch (err) {
+ console.log('Error Connecting to GRPC Server', err)
+ }
return () => next => (action) => {
+ if (!serverStartingActionSent) {
+ serverStartingActionSent = true
+ next({ type: SERVER_STARTING })
+ }
+
+ if (ready && !serverRunningActionSent) {
+ serverRunningActionSent = true
+ next({ type: SERVER_RUNNING })
+ }
+
const call = action && action[GRPC]
if (typeof call === 'undefined' || !call) { return next(action) }
- const { method, types = [], body, model, passthrough = {}, stream = false } = call
- const [REQUEST, SUCCESS, ERROR] = types
+ const { method, body } = call
+ const {
+ params = {},
+ types = [],
+ passthrough = {},
+ schema = data => data,
+ stream = false,
+ } = call
+ const [REQUEST, SUCCESS, ERROR] = _.isArray(types) ? types : [null, types]
REQUEST && next({ type: REQUEST })
- if (stream) { return client[method](body ? { body } : {}) }
+ if (!ready) {
+ return new Promise((resolve, reject) =>
+ reject('GRPC Call Deferred, Server Still Starting'))
+ }
- return new Promise((resolve, reject) => {
- const api = client[method](body || {}, (error, res) => {
- if (error) {
- ERROR && next({ type: ERROR, error })
- reject({ ...error, stream: api })
- } else {
- const data = { [model || method]: res }
- SUCCESS && next({ type: SUCCESS, ...data, ...passthrough })
- resolve({ ...data, stream: api, ...passthrough })
+ if (stream) {
+ if (client[method]) {
+ let streamCall
+ try {
+ if (method === "sendPayment") {
+ streamCall = client[method](metadata, { body })
+ } else {
+ streamCall = client[method](params, metadata)
+ }
+ } catch (err) {
+ console.log('Error From Stream Method', method, err)
+ } finally {
+ // eslint-disable-next-line
+ return streamCall
}
- })
+ }
+ return { on: () => {} }
+ }
+
+ const now = new Date()
+ const deadline = now.setSeconds(now.getSeconds() + 30)
+
+ return new Promise((resolve, reject) => {
+ try {
+ client[method] && client[method](body, metadata, { deadline },
+ (error, res) => {
+ if (error) {
+ ERROR && next({ type: ERROR, error })
+ reject({ ...error })
+ } else {
+ SUCCESS && next({ type: SUCCESS, ...schema(res), ...passthrough, noSchema: res })
+ resolve({ ...schema(res), ...passthrough, noSchema: res })
+ }
+ })
+ } catch (err) {
+ console.log('Error From Method', method, err)
+ reject('Error From Method', method, err)
+ }
})
}
}
diff --git a/packages/redux-grpc-middleware/package.json b/packages/redux-grpc-middleware/package.json
index 99c26593d..5b7b0a4f2 100644
--- a/packages/redux-grpc-middleware/package.json
+++ b/packages/redux-grpc-middleware/package.json
@@ -1,6 +1,6 @@
{
"name": "redux-grpc-middleware",
- "version": "0.1.0",
+ "version": "0.1.1",
"description": "",
"main": "index.js",
"scripts": {
diff --git a/screenshot.png b/screenshot.png
new file mode 100644
index 000000000..9583f8c17
Binary files /dev/null and b/screenshot.png differ