Add mobile account switcher
This commit is contained in:
parent
c5778472f5
commit
16ce14e403
2 changed files with 95 additions and 18 deletions
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { throttle } from 'lodash';
|
||||||
import { Link, NavLink } from 'react-router-dom';
|
import { Link, NavLink } from 'react-router-dom';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
@ -14,8 +15,10 @@ import { closeSidebar } from '../actions/sidebar';
|
||||||
import { shortNumberFormat } from '../utils/numbers';
|
import { shortNumberFormat } from '../utils/numbers';
|
||||||
import { isStaff } from '../utils/accounts';
|
import { isStaff } from '../utils/accounts';
|
||||||
import { makeGetAccount } from '../selectors';
|
import { makeGetAccount } from '../selectors';
|
||||||
import { logOut } from 'soapbox/actions/auth';
|
import { logOut, switchAccount } from 'soapbox/actions/auth';
|
||||||
import ThemeToggle from '../features/ui/components/theme_toggle_container';
|
import ThemeToggle from '../features/ui/components/theme_toggle_container';
|
||||||
|
import { fetchOwnAccounts } from 'soapbox/actions/auth';
|
||||||
|
import { List as ImmutableList } from 'immutable';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
followers: { id: 'account.followers', defaultMessage: 'Followers' },
|
followers: { id: 'account.followers', defaultMessage: 'Followers' },
|
||||||
|
@ -38,17 +41,30 @@ const messages = defineMessages({
|
||||||
news: { id: 'tabs_bar.news', defaultMessage: 'News' },
|
news: { id: 'tabs_bar.news', defaultMessage: 'News' },
|
||||||
donate: { id: 'donate', defaultMessage: 'Donate' },
|
donate: { id: 'donate', defaultMessage: 'Donate' },
|
||||||
info: { id: 'column.info', defaultMessage: 'Server information' },
|
info: { id: 'column.info', defaultMessage: 'Server information' },
|
||||||
|
add_account: { id: 'profile_dropdown.add_account', defaultMessage: 'Add an existing account' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
const me = state.get('me');
|
const me = state.get('me');
|
||||||
const getAccount = makeGetAccount();
|
const getAccount = makeGetAccount();
|
||||||
|
|
||||||
|
const otherAccounts =
|
||||||
|
state
|
||||||
|
.getIn(['auth', 'users'])
|
||||||
|
.keySeq()
|
||||||
|
.reduce((list, id) => {
|
||||||
|
if (id === me) return list;
|
||||||
|
const account = state.getIn(['accounts', id]);
|
||||||
|
return account ? list.push(account) : list;
|
||||||
|
}, ImmutableList());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
account: getAccount(state, me),
|
account: getAccount(state, me),
|
||||||
sidebarOpen: state.get('sidebar').sidebarOpen,
|
sidebarOpen: state.get('sidebar').sidebarOpen,
|
||||||
donateUrl: state.getIn(['patron', 'instance', 'url']),
|
donateUrl: state.getIn(['patron', 'instance', 'url']),
|
||||||
isStaff: isStaff(state.getIn(['accounts', me])),
|
isStaff: isStaff(state.getIn(['accounts', me])),
|
||||||
|
otherAccounts,
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,6 +76,12 @@ const mapDispatchToProps = (dispatch) => ({
|
||||||
dispatch(logOut());
|
dispatch(logOut());
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
},
|
},
|
||||||
|
fetchOwnAccounts() {
|
||||||
|
dispatch(fetchOwnAccounts());
|
||||||
|
},
|
||||||
|
switchAccount(account) {
|
||||||
|
dispatch(switchAccount(account.get('id')));
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @connect(mapStateToProps, mapDispatchToProps)
|
export default @connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
@ -78,8 +100,52 @@ class SidebarMenu extends ImmutablePureComponent {
|
||||||
isStaff: false,
|
isStaff: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
switcher: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSwitchAccount = account => {
|
||||||
|
return e => {
|
||||||
|
this.props.switchAccount(account);
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSwitcherClick = e => {
|
||||||
|
this.setState({ switcher: !this.state.switcher });
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchOwnAccounts = throttle(() => {
|
||||||
|
this.props.fetchOwnAccounts();
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchOwnAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.fetchOwnAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAccount = account => {
|
||||||
|
return (
|
||||||
|
<a href='#' className='sidebar-account' onClick={this.handleSwitchAccount(account)} key={account.get('id')}>
|
||||||
|
<div className='account'>
|
||||||
|
<div className='account__wrapper'>
|
||||||
|
<div className='account__display-name' title={account.get('acct')} href={`/@${account.get('acct')}`} to={`/@${account.get('acct')}`}>
|
||||||
|
<div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>
|
||||||
|
<DisplayName account={account} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { sidebarOpen, onClose, intl, account, onClickLogOut, donateUrl, isStaff } = this.props;
|
const { sidebarOpen, onClose, intl, account, onClickLogOut, donateUrl, isStaff, otherAccounts } = this.props;
|
||||||
|
const { switcher } = this.state;
|
||||||
if (!account) return null;
|
if (!account) return null;
|
||||||
const acct = account.get('acct');
|
const acct = account.get('acct');
|
||||||
|
|
||||||
|
@ -105,24 +171,22 @@ class SidebarMenu extends ImmutablePureComponent {
|
||||||
<Avatar account={account} />
|
<Avatar account={account} />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className='sidebar-menu-profile__name'>
|
<a href='#' className='sidebar-menu-profile__name' onClick={this.handleSwitcherClick}>
|
||||||
<DisplayName account={account} />
|
<DisplayName account={account} />
|
||||||
</div>
|
<Icon id={switcher ? 'caret-up' : 'caret-down'} />
|
||||||
|
</a>
|
||||||
<div className='sidebar-menu-profile__stats'>
|
|
||||||
<NavLink className='sidebar-menu-profile-stat' to={`/@${acct}/followers`} onClick={onClose} title={intl.formatNumber(account.get('followers_count'))}>
|
|
||||||
<strong className='sidebar-menu-profile-stat__value'>{shortNumberFormat(account.get('followers_count'))}</strong>
|
|
||||||
<span className='sidebar-menu-profile-stat__label'>{intl.formatMessage(messages.followers)}</span>
|
|
||||||
</NavLink>
|
|
||||||
<NavLink className='sidebar-menu-profile-stat' to={`/@${acct}/following`} onClick={onClose} title={intl.formatNumber(account.get('following_count'))}>
|
|
||||||
<strong className='sidebar-menu-profile-stat__value'>{shortNumberFormat(account.get('following_count'))}</strong>
|
|
||||||
<span className='sidebar-menu-profile-stat__label'>{intl.formatMessage(messages.follows)}</span>
|
|
||||||
</NavLink>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sidebar-menu__section sidebar-menu__section--borderless'>
|
{switcher && <div className='sidebar-menu__section'>
|
||||||
|
{otherAccounts.map(account => this.renderAccount(account))}
|
||||||
|
|
||||||
|
<NavLink className='sidebar-menu-item' to='/auth/sign_in' onClick={onClose}>
|
||||||
|
<Icon id='plus' />
|
||||||
|
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.add_account)}</span>
|
||||||
|
</NavLink>
|
||||||
|
</div>}
|
||||||
|
|
||||||
|
<div className='sidebar-menu__section'>
|
||||||
<div className='sidebar-menu-item theme-toggle'>
|
<div className='sidebar-menu-item theme-toggle'>
|
||||||
<ThemeToggle showLabel />
|
<ThemeToggle showLabel />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -98,14 +98,23 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&__name {
|
&__name {
|
||||||
display: block;
|
display: flex;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
text-decoration: none;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.display-name__account {
|
.display-name__account {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
color: var(--primary-text-color--faint);
|
color: var(--primary-text-color--faint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i.fa-caret-up,
|
||||||
|
i.fa-caret-down {
|
||||||
|
margin-left: auto;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__stats {
|
&__stats {
|
||||||
|
@ -140,6 +149,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-account {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-menu-item {
|
.sidebar-menu-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 16px 18px;
|
padding: 16px 18px;
|
||||||
|
|
Loading…
Reference in a new issue