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(
allChannels,
channelsSelectors.activeChannels,
channelsSelectors.nonActiveChannels,
channelsSelector,
pendingOpenChannelsSelector,
channelsSelectors.closingPendingChannels,
filterSelector,
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
const filteredArray = (filterKey) => {
switch (filterKey) {
@ -370,6 +371,8 @@ export const currentChannels = createSelector(
return allChannelsArr
case 'ACTIVE_CHANNELS':
return activeChannelsArr
case 'NON_ACTIVE_CHANNELS':
return nonActiveChannelsArr
case 'OPEN_CHANNELS':
return openChannels
case 'OPEN_PENDING_CHANNELS':
@ -417,13 +420,13 @@ const initialState = {
viewType: 0,
filterPulldown: false,
filter: { key: 'ALL_CHANNELS', name: 'All Channels' },
filter: { key: 'ALL_CHANNELS', name: 'All Contacts' },
filters: [
{ key: 'ALL_CHANNELS', name: 'All Channels' },
{ key: 'ACTIVE_CHANNELS', name: 'Active Channels' },
{ key: 'OPEN_CHANNELS', name: 'Open Channels' },
{ key: 'OPEN_PENDING_CHANNELS', name: 'Open Pending Channels' },
{ key: 'CLOSING_PENDING_CHANNELS', name: 'Closing Pending Channels' }
{ key: 'ALL_CHANNELS', name: 'All Contacts' },
{ key: 'ACTIVE_CHANNELS', name: 'Online Contacts' },
{ key: 'NON_ACTIVE_CHANNELS', name: 'Offline Contacts' },
{ key: 'OPEN_PENDING_CHANNELS', name: 'Pending Contacts' },
{ 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 { 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'
@ -19,6 +19,14 @@ import plus from 'icons/plus.svg'
import styles from './Friends.scss'
class Friends extends Component {
constructor(props) {
super(props)
this.state = {
refreshing: false
}
}
componentWillMount() {
const { fetchChannels, fetchPeers, fetchDescribeNetwork } = this.props
@ -29,14 +37,24 @@ class Friends extends Component {
render() {
const {
channels: { searchQuery },
channels: {
searchQuery,
filterPulldown,
filter,
viewType
},
currentChannels,
activeChannels,
nonActiveChannels,
pendingOpenChannels,
closingPendingChannels,
fetchChannels,
updateChannelSearchQuery,
toggleFilterPulldown,
changeFilter,
nonActiveFilters,
openFriendsForm,
friendsFormProps,
@ -44,6 +62,33 @@ class Friends extends Component {
peers
} = 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 (
<div className={styles.friendsContainer}>
<FriendsForm {...friendsFormProps} />
@ -76,7 +121,34 @@ class Friends extends Component {
/>
</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) => {
console.log('channel: ', channel)

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

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

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

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

Loading…
Cancel
Save