You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
299 lines
7.8 KiB
299 lines
7.8 KiB
import { createSelector } from 'reselect'
|
|
import filter from 'lodash/filter'
|
|
import isEmpty from 'lodash/isEmpty'
|
|
|
|
import { tickerSelectors } from './ticker'
|
|
import { btc } from '../utils'
|
|
|
|
// Initial State
|
|
const initialState = {
|
|
// this determines whether or not the network side bar is in search state for a peer or not
|
|
isOpen: false,
|
|
// this determines what form (manual or submit) the user currently has open
|
|
// if this is not null the ChannelForm component will be open
|
|
formType: null,
|
|
|
|
searchQuery: '',
|
|
manualSearchQuery: '',
|
|
contactCapacity: 0,
|
|
node: {},
|
|
showErrors: {
|
|
manualInput: false
|
|
},
|
|
|
|
manualFormOpen: false,
|
|
submitChannelFormOpen: false,
|
|
|
|
showCurrencyFilters: false
|
|
}
|
|
|
|
// Constants
|
|
// ------------------------------------
|
|
export const OPEN_CONTACTS_FORM = 'OPEN_CONTACTS_FORM'
|
|
export const CLOSE_CONTACTS_FORM = 'CLOSE_CONTACTS_FORM'
|
|
|
|
export const OPEN_CHANNEL_FORM_FORM = 'OPEN_CHANNEL_FORM_FORM'
|
|
export const CLOSE_CHANNEL_FORM_FORM = 'CLOSE_CHANNEL_FORM_FORM'
|
|
|
|
export const SET_CHANNEL_FORM_TYPE = 'SET_CHANNEL_FORM_TYPE'
|
|
|
|
export const OPEN_MANUAL_FORM = 'OPEN_MANUAL_FORM'
|
|
export const CLOSE_MANUAL_FORM = 'CLOSE_MANUAL_FORM'
|
|
|
|
export const OPEN_SUBMIT_CHANNEL_FORM = 'OPEN_SUBMIT_CHANNEL_FORM'
|
|
export const CLOSE_SUBMIT_CHANNEL_FORM = 'CLOSE_SUBMIT_CHANNEL_FORM'
|
|
|
|
export const SET_NODE = 'SET_NODE'
|
|
|
|
export const UPDATE_CONTACT_FORM_SEARCH_QUERY = 'UPDATE_CONTACT_FORM_SEARCH_QUERY'
|
|
|
|
export const UPDATE_CONTACT_CAPACITY = 'UPDATE_CONTACT_CAPACITY'
|
|
|
|
export const UPDATE_MANUAL_FORM_ERRORS = 'UPDATE_MANUAL_FORM_ERRORS'
|
|
|
|
export const UPDATE_MANUAL_FORM_SEARCH_QUERY = 'UPDATE_MANUAL_FORM_SEARCH_QUERY'
|
|
|
|
export const SET_CONTACTS_CURRENCY_FILTERS = 'SET_CONTACTS_CURRENCY_FILTERS'
|
|
|
|
// ------------------------------------
|
|
// Actions
|
|
// ------------------------------------
|
|
export function openContactsForm() {
|
|
return {
|
|
type: OPEN_CONTACTS_FORM
|
|
}
|
|
}
|
|
|
|
export function closeContactsForm() {
|
|
return {
|
|
type: CLOSE_CONTACTS_FORM
|
|
}
|
|
}
|
|
|
|
export function openChannelForm() {
|
|
return {
|
|
type: OPEN_CONTACTS_FORM
|
|
}
|
|
}
|
|
|
|
export function closeChannelForm() {
|
|
return {
|
|
type: CLOSE_CONTACTS_FORM
|
|
}
|
|
}
|
|
|
|
export function setChannelFormType(formType) {
|
|
return {
|
|
type: SET_CHANNEL_FORM_TYPE,
|
|
formType
|
|
}
|
|
}
|
|
|
|
export function openManualForm() {
|
|
return {
|
|
type: OPEN_MANUAL_FORM
|
|
}
|
|
}
|
|
|
|
export function closeManualForm() {
|
|
return {
|
|
type: CLOSE_MANUAL_FORM
|
|
}
|
|
}
|
|
|
|
export function openSubmitChannelForm() {
|
|
return {
|
|
type: OPEN_SUBMIT_CHANNEL_FORM
|
|
}
|
|
}
|
|
|
|
export function closeSubmitChannelForm() {
|
|
return {
|
|
type: CLOSE_SUBMIT_CHANNEL_FORM
|
|
}
|
|
}
|
|
|
|
export function updateContactFormSearchQuery(searchQuery) {
|
|
return {
|
|
type: UPDATE_CONTACT_FORM_SEARCH_QUERY,
|
|
searchQuery
|
|
}
|
|
}
|
|
|
|
export function updateManualFormSearchQuery(manualSearchQuery) {
|
|
return {
|
|
type: UPDATE_MANUAL_FORM_SEARCH_QUERY,
|
|
manualSearchQuery
|
|
}
|
|
}
|
|
|
|
export function updateContactCapacity(contactCapacity) {
|
|
return {
|
|
type: UPDATE_CONTACT_CAPACITY,
|
|
contactCapacity
|
|
}
|
|
}
|
|
|
|
export function setNode(node) {
|
|
return {
|
|
type: SET_NODE,
|
|
node
|
|
}
|
|
}
|
|
|
|
export function updateManualFormErrors(errorsObject) {
|
|
return {
|
|
type: UPDATE_MANUAL_FORM_ERRORS,
|
|
errorsObject
|
|
}
|
|
}
|
|
|
|
export function setContactsCurrencyFilters(showCurrencyFilters) {
|
|
return {
|
|
type: SET_CONTACTS_CURRENCY_FILTERS,
|
|
showCurrencyFilters
|
|
}
|
|
}
|
|
|
|
// ------------------------------------
|
|
// Action Handlers
|
|
// ------------------------------------
|
|
const ACTION_HANDLERS = {
|
|
[OPEN_CONTACTS_FORM]: state => ({ ...state, isOpen: true }),
|
|
[CLOSE_CONTACTS_FORM]: state => ({ ...state, isOpen: false }),
|
|
|
|
[SET_CHANNEL_FORM_TYPE]: (state, { formType }) => ({ ...state, formType }),
|
|
|
|
[OPEN_MANUAL_FORM]: state => ({ ...state, manualFormOpen: true }),
|
|
[CLOSE_MANUAL_FORM]: state => ({ ...state, manualFormOpen: false }),
|
|
|
|
[OPEN_SUBMIT_CHANNEL_FORM]: state => ({ ...state, submitChannelFormOpen: true }),
|
|
[CLOSE_SUBMIT_CHANNEL_FORM]: state => ({ ...state, submitChannelFormOpen: false }),
|
|
|
|
[UPDATE_CONTACT_FORM_SEARCH_QUERY]: (state, { searchQuery }) => ({ ...state, searchQuery }),
|
|
|
|
[UPDATE_MANUAL_FORM_SEARCH_QUERY]: (state, { searchQuery }) => ({ ...state, searchQuery }),
|
|
|
|
[UPDATE_CONTACT_CAPACITY]: (state, { contactCapacity }) => ({ ...state, contactCapacity }),
|
|
|
|
[SET_NODE]: (state, { node }) => ({ ...state, node }),
|
|
|
|
[UPDATE_MANUAL_FORM_ERRORS]: (state, { errorsObject }) => ({
|
|
...state,
|
|
showErrors: Object.assign(state.showErrors, errorsObject)
|
|
}),
|
|
|
|
[UPDATE_MANUAL_FORM_SEARCH_QUERY]: (state, { manualSearchQuery }) => ({
|
|
...state,
|
|
manualSearchQuery
|
|
}),
|
|
|
|
[SET_CONTACTS_CURRENCY_FILTERS]: (state, { showCurrencyFilters }) => ({
|
|
...state,
|
|
showCurrencyFilters
|
|
})
|
|
}
|
|
|
|
// ------------------------------------
|
|
// Selector
|
|
// ------------------------------------
|
|
const contactFormSelectors = {}
|
|
const networkNodesSelector = state => state.network.nodes
|
|
const searchQuerySelector = state => state.contactsform.searchQuery
|
|
const manualSearchQuerySelector = state => state.contactsform.manualSearchQuery
|
|
const contactCapacitySelector = state => state.contactsform.contactCapacity
|
|
const currencySelector = state => state.ticker.currency
|
|
|
|
const contactable = node => node.addresses.length > 0
|
|
|
|
// comparator to sort the contacts list with contactable contacts first
|
|
const contactableFirst = (a, b) => {
|
|
if (contactable(a) && !contactable(b)) {
|
|
return -1
|
|
} else if (!contactable(a) && contactable(b)) {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
contactFormSelectors.filteredNetworkNodes = createSelector(
|
|
networkNodesSelector,
|
|
searchQuerySelector,
|
|
(nodes, searchQuery) => {
|
|
// If there is no search query default to showing the first 20 nodes from the nodes array
|
|
// (performance hit to render the entire thing by default)
|
|
// if (!searchQuery.length) { return nodes.sort(contactableFirst).slice(0, 20) }
|
|
|
|
// return an empty array if there is no search query
|
|
if (!searchQuery.length) {
|
|
return []
|
|
}
|
|
|
|
// if there is an '@' in the search query we are assuming they are using the format pubkey@host
|
|
// we can ignore the '@' and the host and just grab the pubkey for our search
|
|
const query = searchQuery.includes('@') ? searchQuery.split('@')[0] : searchQuery
|
|
|
|
// list of the nodes
|
|
const list = filter(
|
|
nodes,
|
|
node => node.alias.includes(query) || node.pub_key.includes(query)
|
|
).sort(contactableFirst)
|
|
|
|
// if we don't limit the nodes returned then we take a huge performance hit
|
|
// rendering thousands of nodes potentially, so we just render 20 for the time being
|
|
return list.slice(0, 20)
|
|
}
|
|
)
|
|
|
|
contactFormSelectors.showManualForm = createSelector(
|
|
searchQuerySelector,
|
|
contactFormSelectors.filteredNetworkNodes,
|
|
(searchQuery, filteredNetworkNodes) => {
|
|
if (!searchQuery.length) {
|
|
return false
|
|
}
|
|
|
|
const connectableNodes = filteredNetworkNodes.filter(node => node.addresses.length > 0)
|
|
|
|
if (!filteredNetworkNodes.length || !connectableNodes.length) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
)
|
|
|
|
contactFormSelectors.manualFormIsValid = createSelector(manualSearchQuerySelector, input => {
|
|
const errors = {}
|
|
if (!input.length || !input.includes('@')) {
|
|
errors.manualInput = 'Invalid format'
|
|
}
|
|
return {
|
|
errors,
|
|
isValid: isEmpty(errors)
|
|
}
|
|
})
|
|
|
|
contactFormSelectors.contactFormUsdAmount = createSelector(
|
|
contactCapacitySelector,
|
|
currencySelector,
|
|
tickerSelectors.currentTicker,
|
|
(amount, currency, ticker) => {
|
|
if (!ticker || !ticker.price_usd) {
|
|
return false
|
|
}
|
|
|
|
return btc.convert(currency, 'usd', amount, ticker.price_usd)
|
|
}
|
|
)
|
|
|
|
export { contactFormSelectors }
|
|
|
|
// ------------------------------------
|
|
// Reducer
|
|
// ------------------------------------
|
|
export default function contactFormReducer(state = initialState, action) {
|
|
const handler = ACTION_HANDLERS[action.type]
|
|
|
|
return handler ? handler(state, action) : state
|
|
}
|
|
|