Browse Source

feature(contacts): add filter and refresh to contacts

renovate/lint-staged-8.x
Jack Mallers 7 years ago
parent
commit
d817ecc426
  1. 17
      app/reducers/channels.js
  2. 80
      app/routes/friends/components/Friends.js
  3. 134
      app/routes/friends/components/Friends.scss
  4. 5
      app/routes/friends/containers/FriendsContainer.js

17
app/reducers/channels.js

@ -357,12 +357,13 @@ const allChannels = createSelector(
export const currentChannels = createSelector( export const currentChannels = createSelector(
allChannels, allChannels,
channelsSelectors.activeChannels, channelsSelectors.activeChannels,
channelsSelectors.nonActiveChannels,
channelsSelector, channelsSelector,
pendingOpenChannelsSelector, pendingOpenChannelsSelector,
channelsSelectors.closingPendingChannels, channelsSelectors.closingPendingChannels,
filterSelector, filterSelector,
channelSearchQuerySelector, channelSearchQuerySelector,
(allChannelsArr, activeChannelsArr, openChannels, pendingOpenChannels, pendingClosedChannels, filter, searchQuery) => { (allChannelsArr, activeChannelsArr, nonActiveChannelsArr, openChannels, pendingOpenChannels, pendingClosedChannels, filter, searchQuery) => {
// Helper function to deliver correct channel array based on filter // Helper function to deliver correct channel array based on filter
const filteredArray = (filterKey) => { const filteredArray = (filterKey) => {
switch (filterKey) { switch (filterKey) {
@ -370,6 +371,8 @@ export const currentChannels = createSelector(
return allChannelsArr return allChannelsArr
case 'ACTIVE_CHANNELS': case 'ACTIVE_CHANNELS':
return activeChannelsArr return activeChannelsArr
case 'NON_ACTIVE_CHANNELS':
return nonActiveChannelsArr
case 'OPEN_CHANNELS': case 'OPEN_CHANNELS':
return openChannels return openChannels
case 'OPEN_PENDING_CHANNELS': case 'OPEN_PENDING_CHANNELS':
@ -417,13 +420,13 @@ const initialState = {
viewType: 0, viewType: 0,
filterPulldown: false, filterPulldown: false,
filter: { key: 'ALL_CHANNELS', name: 'All Channels' }, filter: { key: 'ALL_CHANNELS', name: 'All Contacts' },
filters: [ filters: [
{ key: 'ALL_CHANNELS', name: 'All Channels' }, { key: 'ALL_CHANNELS', name: 'All Contacts' },
{ key: 'ACTIVE_CHANNELS', name: 'Active Channels' }, { key: 'ACTIVE_CHANNELS', name: 'Online Contacts' },
{ key: 'OPEN_CHANNELS', name: 'Open Channels' }, { key: 'NON_ACTIVE_CHANNELS', name: 'Offline Contacts' },
{ key: 'OPEN_PENDING_CHANNELS', name: 'Open Pending Channels' }, { key: 'OPEN_PENDING_CHANNELS', name: 'Pending Contacts' },
{ key: 'CLOSING_PENDING_CHANNELS', name: 'Closing Pending Channels' } { key: 'CLOSING_PENDING_CHANNELS', name: 'Closing Contacts' }
] ]
} }

80
app/routes/friends/components/Friends.js

@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import Isvg from 'react-inlinesvg' import Isvg from 'react-inlinesvg'
import { MdSearch } from 'react-icons/lib/md' import { MdSearch } from 'react-icons/lib/md'
import { FaCircle } from 'react-icons/lib/fa' import { FaAngleDown, FaRepeat } from 'react-icons/lib/fa'
import { btc } from 'utils' import { btc } from 'utils'
@ -19,6 +19,14 @@ import plus from 'icons/plus.svg'
import styles from './Friends.scss' import styles from './Friends.scss'
class Friends extends Component { class Friends extends Component {
constructor(props) {
super(props)
this.state = {
refreshing: false
}
}
componentWillMount() { componentWillMount() {
const { fetchChannels, fetchPeers, fetchDescribeNetwork } = this.props const { fetchChannels, fetchPeers, fetchDescribeNetwork } = this.props
@ -29,14 +37,24 @@ class Friends extends Component {
render() { render() {
const { const {
channels: { searchQuery }, channels: {
searchQuery,
filterPulldown,
filter,
viewType
},
currentChannels, currentChannels,
activeChannels, activeChannels,
nonActiveChannels, nonActiveChannels,
pendingOpenChannels, pendingOpenChannels,
closingPendingChannels, closingPendingChannels,
fetchChannels,
updateChannelSearchQuery, updateChannelSearchQuery,
toggleFilterPulldown,
changeFilter,
nonActiveFilters,
openFriendsForm, openFriendsForm,
friendsFormProps, friendsFormProps,
@ -44,6 +62,33 @@ class Friends extends Component {
peers peers
} = this.props } = this.props
const refreshClicked = () => {
// turn the spinner on
this.setState({ refreshing: true })
// store event in icon so we dont get an error when react clears it
const icon = this.repeat.childNodes
// fetch channels
fetchChannels()
// wait for the svg to appear as child
const svgTimeout = setTimeout(() => {
if (icon[0].tagName === 'svg') {
// spin icon for 1 sec
icon[0].style.animation = 'spin 1000ms linear 1'
clearTimeout(svgTimeout)
}
}, 1)
// clear animation after the second so we can reuse it
const refreshTimeout = setTimeout(() => {
icon[0].style.animation = ''
this.setState({ refreshing: false })
clearTimeout(refreshTimeout)
}, 1000)
}
return ( return (
<div className={styles.friendsContainer}> <div className={styles.friendsContainer}>
<FriendsForm {...friendsFormProps} /> <FriendsForm {...friendsFormProps} />
@ -76,7 +121,34 @@ class Friends extends Component {
/> />
</div> </div>
<ul className={styles.friends}> <div className={styles.filtersContainer}>
<section>
<h2 onClick={toggleFilterPulldown} className={styles.filterTitle}>
{filter.name} <span className={filterPulldown && styles.pulldown}><FaAngleDown /></span>
</h2>
<ul className={`${styles.filters} ${filterPulldown && styles.active}`}>
{
nonActiveFilters.map(f => (
<li key={f.key} onClick={() => changeFilter(f)}>
{f.name}
</li>
))
}
</ul>
</section>
<section className={styles.refreshContainer}>
<span className={styles.refresh} onClick={refreshClicked} ref={(ref) => { this.repeat = ref }}>
{
this.state.refreshing ?
<FaRepeat />
:
'Refresh'
}
</span>
</section>
</div>
<ul className={`${styles.friends} ${filterPulldown && styles.fade}`}>
{ {
currentChannels.length > 0 && currentChannels.map((channel, index) => { currentChannels.length > 0 && currentChannels.map((channel, index) => {
console.log('channel: ', channel) console.log('channel: ', channel)

134
app/routes/friends/components/Friends.scss

@ -83,107 +83,75 @@
} }
} }
.friends { .filtersContainer {
padding: 10px 60px 60px 60px; position: relative;
}
.friend {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
padding: 30px 0; padding: 20px 40px;
border-bottom: 1px solid $traditionalgrey;
.limits {
display: flex;
flex-direction: row;
justify-content: space-between;
div { h2, h2 span {
margin: 0 10px; color: $bluegrey;
cursor: pointer;
transition: color 0.25s;
h4 { &:hover {
font-size: 12px; color: lighten($bluegrey, 10%);
margin-bottom: 20px;
}
} }
} }
h2, .filters li {
text-transform: uppercase;
letter-spacing: 1.5px;
color: $darkestgrey;
font-size: 14px;
font-weight: 400;
}
.info { h2 span.pulldown {
p { color: $main;
margin-bottom: 20px; }
&.online {
color: $green;
svg {
color: $green;
}
}
&.pending {
color: $orange;
svg {
color: $orange;
}
i {
margin-left: 5px;
color: $darkestgrey;
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}
&.closing {
color: $red;
svg {
color: $red;
}
i {
margin-left: 5px;
color: $darkestgrey;
cursor: pointer;
&:hover { .filters {
text-decoration: underline; display: none;
}
&.active {
display: block;
position: absolute;
bottom: -100px;
z-index: 10;
li {
margin: 5px 0;
cursor: pointer;
&:hover {
color: $main;
} }
} }
}
}
.refreshContainer {
text-align: right;
cursor: pointer;
svg, span { .refresh {
display: inline-block; text-decoration: underline;
vertical-align: top;
}
svg { svg {
margin-right: 5px;
width: 12px;
height: 12px;
color: $darkestgrey;
}
span {
font-size: 12px; font-size: 12px;
} }
} }
}
}
h2 { .friends {
color: $black; padding: 10px 60px 60px 60px;
font-size: 14px; opacity: 1;
font-weight: bold; transition: all 0.25s;
letter-spacing: 1.3px;
span { &.fade {
color: $darkestgrey; opacity: 0.05;
margin-left: 5px;
}
}
} }
} }

5
app/routes/friends/containers/FriendsContainer.js

@ -6,6 +6,8 @@ import {
openChannel, openChannel,
updateChannelSearchQuery, updateChannelSearchQuery,
toggleFilterPulldown,
changeFilter,
currentChannels, currentChannels,
channelsSelectors channelsSelectors
@ -30,6 +32,8 @@ const mapDispatchToProps = {
updateFriendFormSearchQuery, updateFriendFormSearchQuery,
openChannel, openChannel,
updateChannelSearchQuery, updateChannelSearchQuery,
toggleFilterPulldown,
changeFilter,
fetchChannels, fetchChannels,
fetchPeers, fetchPeers,
@ -50,6 +54,7 @@ const mapStateToProps = state => ({
pendingOpenChannels: channelsSelectors.pendingOpenChannels(state), pendingOpenChannels: channelsSelectors.pendingOpenChannels(state),
pendingOpenChannelPubkeys: channelsSelectors.pendingOpenChannelPubkeys(state), pendingOpenChannelPubkeys: channelsSelectors.pendingOpenChannelPubkeys(state),
closingPendingChannels: channelsSelectors.closingPendingChannels(state), closingPendingChannels: channelsSelectors.closingPendingChannels(state),
nonActiveFilters: channelsSelectors.nonActiveFilters(state),
filteredNetworkNodes: friendFormSelectors.filteredNetworkNodes(state) filteredNetworkNodes: friendFormSelectors.filteredNetworkNodes(state)
}) })

Loading…
Cancel
Save