progress
This commit is contained in:
@@ -17,7 +17,7 @@ const messages = defineMessages({
|
||||
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
|
||||
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
|
||||
public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
|
||||
community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Community timeline' },
|
||||
community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Community feed' },
|
||||
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
||||
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
||||
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new gab' },
|
||||
|
||||
@@ -12,15 +12,9 @@ const messages = defineMessages({
|
||||
reject: { id: 'follow_request.reject', defaultMessage: 'Reject' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
account: getAccount(state, props.id),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
const makeMapStateToProps = () => ({
|
||||
account: makeGetAccount()(state, props.id),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch, { id }) => ({
|
||||
onAuthorize() {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './list'
|
||||
@@ -1,66 +0,0 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { removeFromListAdder, addToListAdder } from '../../../../actions/lists';
|
||||
import Button from '../../../../components/button';
|
||||
import Icon from '../../../../components/icon';
|
||||
|
||||
const messages = defineMessages({
|
||||
remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
|
||||
add: { id: 'lists.account.add', defaultMessage: 'Add to list' },
|
||||
});
|
||||
|
||||
const MapStateToProps = (state, { listId, added }) => ({
|
||||
list: state.get('lists').get(listId),
|
||||
added: typeof added === 'undefined' ? state.getIn(['listAdder', 'lists', 'items']).includes(listId) : added,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch, { listId }) => ({
|
||||
onRemove: () => dispatch(removeFromListAdder(listId)),
|
||||
onAdd: () => dispatch(addToListAdder(listId)),
|
||||
});
|
||||
|
||||
// : todo :
|
||||
|
||||
export default
|
||||
@connect(MapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class List extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
list: ImmutablePropTypes.map.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
onAdd: PropTypes.func.isRequired,
|
||||
added: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
added: false,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { list, intl, onRemove, onAdd, added } = this.props;
|
||||
|
||||
return (
|
||||
<div className='list'>
|
||||
<div className='list__wrapper'>
|
||||
<div className='list__name'>
|
||||
<Icon id='list-ul' className='list__name-icon' fixedWidth />
|
||||
{list.get('title')}
|
||||
</div>
|
||||
|
||||
<div className='list__btn-block'>
|
||||
{
|
||||
added ?
|
||||
<Button icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} />
|
||||
:
|
||||
<Button icon='plus' title={intl.formatMessage(messages.add)} onClick={onAdd} />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
.list {
|
||||
padding: 4px;
|
||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
||||
|
||||
&__wrapper {
|
||||
display: flex;
|
||||
|
||||
.account__relationship {
|
||||
padding: 8px 5px 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&__name {
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
&__name-icon {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&__btn-block {
|
||||
height: auto;
|
||||
position: relative;
|
||||
padding: 0 0 0 5px;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './list_adder'
|
||||
@@ -1,90 +0,0 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { getOrderedLists } from '../../selectors'
|
||||
import { setupListAdder, resetListAdder } from '../../actions/lists';
|
||||
import List from './components/list';
|
||||
import Account from '../../components/account';
|
||||
import Button from '../../components/button';
|
||||
// import NewListForm from '../lists_directory/components/new_list_form';
|
||||
|
||||
const mapStateToProps = (state, { accountId }) => ({
|
||||
listIds: getOrderedLists(state).map(list => list.get('id')),
|
||||
account: state.getIn(['accounts', accountId]),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onInitialize: accountId => dispatch(setupListAdder(accountId)),
|
||||
onReset: () => dispatch(resetListAdder()),
|
||||
});
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
subheading: { id: 'lists.subheading', defaultMessage: 'Your lists' },
|
||||
add: { id: 'lists.new.create', defaultMessage: 'Add List' },
|
||||
headerTitle: { id: 'list_adder.header_title', defaultMessage: 'Add or Remove from Lists' },
|
||||
});
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class ListAdder extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
accountId: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onInitialize: PropTypes.func.isRequired,
|
||||
onReset: PropTypes.func.isRequired,
|
||||
listIds: ImmutablePropTypes.list.isRequired,
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { onInitialize, accountId } = this.props;
|
||||
onInitialize(accountId);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.onReset();
|
||||
}
|
||||
|
||||
onClickClose = () => {
|
||||
this.props.onClose('LIST_ADDER');
|
||||
};
|
||||
|
||||
render() {
|
||||
const { listIds, intl, account } = this.props;
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal compose-modal'>
|
||||
<div className='compose-modal__header'>
|
||||
<h3 className='compose-modal__header__title'>
|
||||
{intl.formatMessage(messages.headerTitle)}
|
||||
</h3>
|
||||
<Button className='compose-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={this.onClickClose} size={20} />
|
||||
</div>
|
||||
<div className='compose-modal__content'>
|
||||
<div className='list-adder'>
|
||||
<div className='list-adder__account'>
|
||||
<Account account={account} displayOnly/>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
{ /* <NewListForm /> */ }
|
||||
|
||||
<br />
|
||||
|
||||
<div className='list-adder__lists'>
|
||||
{
|
||||
listIds.map(ListId => <List key={ListId} listId={ListId} />)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
316
app/javascript/gabsocial/features/list_edit.js
Normal file
316
app/javascript/gabsocial/features/list_edit.js
Normal file
@@ -0,0 +1,316 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import isObject from 'lodash.isobject'
|
||||
import {
|
||||
setupListEditor,
|
||||
resetListEditor,
|
||||
removeFromListEditor,
|
||||
addToListEditor,
|
||||
fetchListSuggestions,
|
||||
clearListSuggestions,
|
||||
changeListSuggestions,
|
||||
} from '../actions/lists'
|
||||
import { openModal } from '../actions/modal'
|
||||
import {
|
||||
MODAL_LIST_EDITOR,
|
||||
MODAL_LIST_DELETE,
|
||||
} from '../constants'
|
||||
import Account from '../components/account'
|
||||
import Button from '../components/button'
|
||||
import Divider from '../components/divider'
|
||||
import Input from '../components/input'
|
||||
import TabBar from '../components/tab_bar'
|
||||
import Text from '../components/text'
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
save: { id: 'lists.new.save_title', defaultMessage: 'Save Title' },
|
||||
changeTitle: { id: 'lists.edit.submit', defaultMessage: 'Change title' },
|
||||
addToList: { id: 'lists.account.add', defaultMessage: 'Add to list' },
|
||||
removeFromList: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
|
||||
editList: { id: 'lists.edit', defaultMessage: 'Edit list' },
|
||||
editListTitle: { id: 'lists.new.edit_title_placeholder', defaultMessage: 'Edit list title' },
|
||||
remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
|
||||
add: { id: 'lists.account.add', defaultMessage: 'Add to list' },
|
||||
search: { id: 'lists.search', defaultMessage: 'Search people...' },
|
||||
searchMembers: { id: 'lists.search_members', defaultMessage: 'Search members...' },
|
||||
searchTitle: { id: 'tabs_bar.search', defaultMessage: 'Search' },
|
||||
})
|
||||
|
||||
const mapStateToProps = (state, { params, id }) => {
|
||||
const listId = isObject(params) ? params['id'] : id
|
||||
|
||||
return {
|
||||
listId,
|
||||
list: state.getIn(['lists', listId]),
|
||||
title: state.getIn(['listEditor', 'title']),
|
||||
disabled: !state.getIn(['listEditor', 'isChanged']),
|
||||
accountIds: state.getIn(['listEditor', 'accounts', 'items']),
|
||||
searchAccountIds: state.getIn(['listEditor', 'suggestions', 'items']),
|
||||
searchSuggestionsValue: state.getIn(['listEditor', 'suggestions', 'value']),
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
onDeleteList(list) {
|
||||
dispatch(openModal(MODAL_LIST_DELETE, { list }))
|
||||
},
|
||||
|
||||
onChangeTitle(value) {
|
||||
dispatch(changeListEditorTitle(value))
|
||||
},
|
||||
|
||||
onUpdateList() {
|
||||
dispatch(submitListEditor(false))
|
||||
},
|
||||
|
||||
onInitialize(listId) {
|
||||
dispatch(setupListEditor(listId))
|
||||
},
|
||||
|
||||
onReset() {
|
||||
dispatch(resetListEditor())
|
||||
},
|
||||
|
||||
onRemoveAccountFromList(accountId) {
|
||||
dispatch(removeFromListEditor(accountId))
|
||||
},
|
||||
|
||||
onAddAccountToList(accountId) {
|
||||
dispatch(addToListEditor(accountId))
|
||||
},
|
||||
|
||||
onSubmitSearchSuggestions(value) {
|
||||
dispatch(fetchListSuggestions(value))
|
||||
},
|
||||
|
||||
onClearSearchSuggestions() {
|
||||
dispatch(clearListSuggestions())
|
||||
},
|
||||
|
||||
onChangeSuggestions(value) {
|
||||
dispatch(changeListSuggestions(value))
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class ListEdit extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
list: ImmutablePropTypes.map,
|
||||
title: PropTypes.string,
|
||||
listId: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onInitialize: PropTypes.func.isRequired,
|
||||
onReset: PropTypes.func.isRequired,
|
||||
searchSuggestionsValue: PropTypes.string.isRequired,
|
||||
accountIds: ImmutablePropTypes.list.isRequired,
|
||||
searchAccountIds: ImmutablePropTypes.list.isRequired,
|
||||
onRemoveAccountFromList: PropTypes.func.isRequired,
|
||||
onAddAccountToList: PropTypes.func.isRequired,
|
||||
onChangeSuggestions: PropTypes.func.isRequired,
|
||||
onClearSearchSuggestions: PropTypes.func.isRequired,
|
||||
onSubmitSearchSuggestions: PropTypes.func.isRequired,
|
||||
onDeleteList: PropTypes.func.isRequired,
|
||||
tab: PropTypes.string,
|
||||
}
|
||||
|
||||
state = {
|
||||
activeTab: this.props.tab || 'members'
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { onInitialize, listId } = this.props
|
||||
if (listId) {
|
||||
onInitialize(listId)
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.listId !== prevProps.listId) {
|
||||
this.props.onInitialize(this.props.listId)
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.onReset()
|
||||
}
|
||||
|
||||
handleChangeTab = (tab) => {
|
||||
this.setState({ activeTab: tab })
|
||||
}
|
||||
|
||||
onClickClose = () => {
|
||||
this.props.onClose(MODAL_LIST_EDITOR)
|
||||
}
|
||||
|
||||
handleOnDeleteList = () => {
|
||||
this.props.onDeleteList(this.props.list)
|
||||
}
|
||||
|
||||
handleAddOrRemoveFromList = (accountId) => {
|
||||
if (this.props.accountIds.includes(accountId)) {
|
||||
this.props.onRemoveAccountFromList(accountId)
|
||||
} else {
|
||||
this.props.onAddAccountToList(accountId)
|
||||
}
|
||||
}
|
||||
|
||||
handleSearchSuggestionsChange = (value) => {
|
||||
this.props.onChangeSuggestions(value)
|
||||
}
|
||||
|
||||
handleSearchSuggestionsKeyUp = (e) => {
|
||||
if (e.keyCode === 13) {
|
||||
this.props.onSubmitSearchSuggestions(this.props.searchSuggestionsValue)
|
||||
}
|
||||
}
|
||||
|
||||
handleSearchSuggestionsSubmit = () => {
|
||||
this.props.onSubmitSearchSuggestions(this.props.searchSuggestionsValue)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
title,
|
||||
accountIds,
|
||||
searchAccountIds,
|
||||
intl,
|
||||
searchSuggestionsValue,
|
||||
} = this.props
|
||||
const { activeTab } = this.state
|
||||
|
||||
// : todo : save new list title
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={[_s.default, _s.borderTop1PX, _s.borderColorSecondary].join(' ')}>
|
||||
<div className={[_s.default, _s.z4, _s.bgPrimary, _s.px15, _s.top0, _s.posSticky, _s.borderBottom1PX, _s.borderColorSecondary,].join(' ')}>
|
||||
<TabBar
|
||||
tabs={[
|
||||
{
|
||||
title: 'Members list',
|
||||
onClick: () => this.handleChangeTab('members'),
|
||||
active: activeTab === 'members',
|
||||
},
|
||||
{
|
||||
title: 'Add new',
|
||||
onClick: () => this.handleChangeTab('add-new'),
|
||||
active: activeTab === 'add-new',
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
onClick: () => this.handleChangeTab('settings'),
|
||||
active: activeTab === 'settings',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{
|
||||
activeTab === 'members' &&
|
||||
<div className={[_s.default, _s.mb10, _s.py10].join(' ')}>
|
||||
<div className={[_s.default, _s.pb10, _s.pt5].join(' ')}>
|
||||
<div className={[_s.default].join(' ')}>
|
||||
<Text weight='bold' size='small' color='secondary' className={[_s.default, _s.px15, _s.mt5, _s.mb15].join(' ')}>
|
||||
Total members ({accountIds.size})
|
||||
</Text>
|
||||
{
|
||||
accountIds &&
|
||||
accountIds.map((accountId) => (
|
||||
<Account
|
||||
compact
|
||||
key={`remove-from-list-${accountId}`}
|
||||
id={accountId}
|
||||
onActionClick={() => this.handleAddOrRemoveFromList(accountId)}
|
||||
actionIcon={'subtract'}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
activeTab === 'settings' &&
|
||||
<div className={[_s.default, _s.mb10, _s.pb10, _s.px15].join(' ')}>
|
||||
<div className={[_s.default, _s.py15].join(' ')}>
|
||||
<Input
|
||||
title={intl.formatMessage(messages.editListTitle)}
|
||||
placeholder='My new list title...'
|
||||
value={title}
|
||||
// onChange={onChange}
|
||||
// onSubmit={onSubmit}
|
||||
// disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
<Divider />
|
||||
<div className={_s.mb10}>
|
||||
<Button
|
||||
onClick={this.handleOnDeleteList}
|
||||
backgroundColor='danger'
|
||||
>
|
||||
Delete List
|
||||
</Button>
|
||||
</div>
|
||||
<Text size='extraSmall' color='secondary'>
|
||||
Once you delete a list you cannot retrieve it.
|
||||
</Text>
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
activeTab === 'add-new' &&
|
||||
<div className={[_s.default, _s.mb10, _s.py10].join(' ')}>
|
||||
<div className={[_s.default, _s.px15].join(' ')}>
|
||||
<Input
|
||||
placeholder={intl.formatMessage(messages.search)}
|
||||
value={searchSuggestionsValue}
|
||||
onChange={this.handleSearchSuggestionsChange}
|
||||
onKeyUp={this.handleSearchSuggestionsKeyUp}
|
||||
handleSubmit={this.handleSearchSuggestionsSubmit}
|
||||
title={intl.formatMessage(messages.searchTitle)}
|
||||
prependIcon='search'
|
||||
hideLabel
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.pt10].join(' ')}>
|
||||
<div className={[_s.default].join(' ')}>
|
||||
<Text weight='bold' size='small' color='secondary' className={[_s.default, _s.px15, _s.mt5, _s.mb15].join(' ')}>
|
||||
Search results ({searchAccountIds.size})
|
||||
</Text>
|
||||
{
|
||||
searchAccountIds &&
|
||||
searchAccountIds.map((accountId) => {
|
||||
if (accountIds.includes(accountId)) return null
|
||||
return (
|
||||
<Account
|
||||
key={`add-to-list-${accountId}`}
|
||||
id={accountId}
|
||||
compact
|
||||
onActionClick={() => this.handleAddOrRemoveFromList(accountId)}
|
||||
actionIcon='add'
|
||||
/>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { removeFromListEditor, addToListEditor } from '../../../actions/lists';
|
||||
import { makeGetAccount } from '../../../selectors';
|
||||
import Avatar from '../../../components/avatar';
|
||||
import DisplayName from '../../../components/display_name';
|
||||
import Button from '../../../components/button';
|
||||
|
||||
const messages = defineMessages({
|
||||
remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
|
||||
add: { id: 'lists.account.add', defaultMessage: 'Add to list' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const mapStateToProps = (state, { accountId, added }) => ({
|
||||
account: getAccount(state, accountId),
|
||||
added: typeof added === 'undefined' ? state.getIn(['listEditor', 'accounts', 'items']).includes(accountId) : added,
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { accountId }) => ({
|
||||
onRemove: () => dispatch(removeFromListEditor(accountId)),
|
||||
onAdd: () => dispatch(addToListEditor(accountId)),
|
||||
});
|
||||
|
||||
export default
|
||||
@connect(makeMapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class Account extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
onAdd: PropTypes.func.isRequired,
|
||||
added: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
added: false,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { account, intl, onRemove, onAdd, added } = this.props;
|
||||
|
||||
let button;
|
||||
|
||||
if (added) {
|
||||
button = <Button icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
|
||||
} else {
|
||||
button = <Button icon='plus' title={intl.formatMessage(messages.add)} onClick={onAdd} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='account'>
|
||||
<div className='account__wrapper'>
|
||||
<div className='account__display-name'>
|
||||
<div className='account__avatar-wrapper'>
|
||||
<Avatar account={account} size={36} />
|
||||
</div>
|
||||
<DisplayName account={account} />
|
||||
</div>
|
||||
|
||||
<div className='account__relationship'>
|
||||
{button}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { changeListEditorTitle, submitListEditor } from '../../../../actions/lists';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'lists.edit.submit', defaultMessage: 'Change title' },
|
||||
save: { id: 'lists.new.save_title', defaultMessage: 'Save Title' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
value: state.getIn(['listEditor', 'title']),
|
||||
disabled: !state.getIn(['listEditor', 'isChanged']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onChange: value => dispatch(changeListEditorTitle(value)),
|
||||
onSubmit: () => dispatch(submitListEditor(false)),
|
||||
});
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class ListForm extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { value, disabled, intl, onSubmit, onChange } = this.props;
|
||||
|
||||
return null;
|
||||
|
||||
// return (
|
||||
// <ColumnInlineForm
|
||||
// value={value}
|
||||
// onChange={onChange}
|
||||
// onSubmit={onSubmit}
|
||||
// label={intl.formatMessage(messages.title)}
|
||||
// btnTitle={intl.formatMessage(messages.save)}
|
||||
// disabled={disabled}
|
||||
// />
|
||||
// );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './edit_list_form'
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './list_editor_search'
|
||||
@@ -1,68 +0,0 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../../actions/lists';
|
||||
import Search from '../../../../components/search';
|
||||
|
||||
const messages = defineMessages({
|
||||
search: { id: 'lists.search', defaultMessage: 'Search among people you follow' },
|
||||
searchTitle: { id: 'tabs_bar.search', defaultMessage: 'Search' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
value: state.getIn(['listEditor', 'suggestions', 'value']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onSubmit: (value) => dispatch(fetchListSuggestions(value)),
|
||||
onClear: () => dispatch(clearListSuggestions()),
|
||||
onChange: (value) => dispatch(changeListSuggestions(value)),
|
||||
});
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class ListEditorSearch extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
onClear: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleChange = (value) => {
|
||||
this.props.onChange(value);
|
||||
}
|
||||
|
||||
handleKeyUp = e => {
|
||||
if (e.keyCode === 13) {
|
||||
this.props.onSubmit(this.props.value);
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmit = () => {
|
||||
this.props.onSubmit(this.props.value);
|
||||
}
|
||||
|
||||
handleClear = () => {
|
||||
this.props.onClear();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { value, intl } = this.props;
|
||||
|
||||
return (
|
||||
<Search
|
||||
className='list-editor-search'
|
||||
placeholder={intl.formatMessage(messages.search)}
|
||||
value={value}
|
||||
onChange={this.handleChange}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
handleSubmit={this.handleSubmit}
|
||||
handleClear={this.handleClear}
|
||||
searchTitle={intl.formatMessage(messages.searchTitle)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './list_edit'
|
||||
@@ -1,127 +0,0 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import isObject from 'lodash.isobject'
|
||||
import { setupListEditor, resetListEditor } from '../../actions/lists'
|
||||
import Account from './components/account'
|
||||
import ListEditorSearch from './components/list_editor_search'
|
||||
import EditListForm from './components/edit_list_form/edit_list_form'
|
||||
import Button from '../../components/button'
|
||||
import Form from '../../components/form'
|
||||
import Input from '../../components/input'
|
||||
|
||||
const mapStateToProps = (state, { params }) => {
|
||||
|
||||
console.log("params:", params)
|
||||
|
||||
const listId = isObject(params) ? params['id'] : null
|
||||
|
||||
return {
|
||||
listId,
|
||||
title: state.getIn(['listEditor', 'title']),
|
||||
accountIds: state.getIn(['listEditor', 'accounts', 'items']),
|
||||
searchAccountIds: state.getIn(['listEditor', 'suggestions', 'items']),
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onInitialize: (listId) => dispatch(setupListEditor(listId)),
|
||||
onReset: () => dispatch(resetListEditor()),
|
||||
})
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
changeTitle: { id: 'lists.edit.submit', defaultMessage: 'Change title' },
|
||||
addToList: { id: 'lists.account.add', defaultMessage: 'Add to list' },
|
||||
removeFromList: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
|
||||
editList: { id: 'lists.edit', defaultMessage: 'Edit list' },
|
||||
editListTitle: { id: 'lists.new.edit_title_placeholder', defaultMessage: 'Edit list title' },
|
||||
})
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class ListEdit extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
title: PropTypes.string,
|
||||
listId: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onInitialize: PropTypes.func.isRequired,
|
||||
onReset: PropTypes.func.isRequired,
|
||||
accountIds: ImmutablePropTypes.list.isRequired,
|
||||
searchAccountIds: ImmutablePropTypes.list.isRequired,
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { onInitialize, listId } = this.props
|
||||
console.log("listId:", listId)
|
||||
if (listId) {
|
||||
onInitialize(listId)
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.onReset()
|
||||
}
|
||||
|
||||
onClickClose = () => {
|
||||
this.props.onClose('LIST_ADDER')
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
title,
|
||||
accountIds,
|
||||
searchAccountIds,
|
||||
intl
|
||||
} = this.props
|
||||
|
||||
console.log("title:", title)
|
||||
|
||||
return (
|
||||
<Form>
|
||||
<Input
|
||||
title={intl.formatMessage(messages.editListTitle)}
|
||||
placeholder='My new list title...'
|
||||
value={title}
|
||||
// onChange={onChange}
|
||||
// onSubmit={onSubmit}
|
||||
// disabled={disabled}
|
||||
/>
|
||||
|
||||
<div className='compose-modal__header'>
|
||||
<h3 className='compose-modal__header__title'>
|
||||
{intl.formatMessage(messages.editList)}
|
||||
</h3>
|
||||
<Button className='compose-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={this.onClickClose} size={20} />
|
||||
</div>
|
||||
<div className='compose-modal__content'>
|
||||
<div className='list-editor'>
|
||||
<EditListForm />
|
||||
<br />
|
||||
|
||||
{
|
||||
accountIds.size > 0 &&
|
||||
<div>
|
||||
<div className='list-editor__accounts'>
|
||||
{accountIds.map(accountId => <Account key={accountId} accountId={accountId} added />)}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<br />
|
||||
<ListEditorSearch />
|
||||
<div className='list-editor__accounts'>
|
||||
{searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} />)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Form>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -71,7 +71,8 @@ class ListTimeline extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
handleEditClick = () => {
|
||||
this.props.dispatch(openModal('LIST_EDITOR', { listId: this.props.params.id }))
|
||||
console.log("handleEditClick:", this.props.params.id)
|
||||
this.props.dispatch(openModal('LIST_EDITOR', { id: this.props.params.id }))
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -86,20 +87,22 @@ class ListTimeline extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
const emptyMessage = (
|
||||
<div className={[_s.default, _s.py15, _s.px15].join(' ')}>
|
||||
<div className={[_s.default, _s.py15, _s.px15, _s.alignItemsCenter].join(' ')}>
|
||||
<FormattedMessage
|
||||
id='empty_column.list'
|
||||
defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.'
|
||||
/>
|
||||
|
||||
<Button
|
||||
onClick={this.handleEditClick}
|
||||
className={[_s.mt10]}
|
||||
>
|
||||
<Text color='inherit' align='center'>
|
||||
<FormattedMessage id='list.click_to_add' defaultMessage='Click here to add people' />
|
||||
</Text>
|
||||
</Button>
|
||||
<div className={_s.mt10}>
|
||||
<Button
|
||||
onClick={this.handleEditClick}
|
||||
className={[_s.mt10]}
|
||||
>
|
||||
<Text color='inherit' align='center'>
|
||||
<FormattedMessage id='list.click_to_add' defaultMessage='Click here to add people' />
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,50 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { fetchStatus } from '../actions/statuses'
|
||||
import StatusContainer from '../containers/status_container'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const statusId = props.id || props.params.statusId
|
||||
|
||||
return {
|
||||
status: state.getIn(['statuses', statusId]),
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onFetchStatus: (id) => dispatch(fetchStatus(id)),
|
||||
})
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
class Status extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
onFetchStatus: PropTypes.func.isRequired,
|
||||
params: PropTypes.object,
|
||||
status: ImmutablePropTypes.map,
|
||||
}
|
||||
|
||||
updateOnProps = [
|
||||
'params',
|
||||
'status',
|
||||
]
|
||||
|
||||
componentDidMount() {
|
||||
const statusId = this.props.id || this.props.params.statusId
|
||||
this.props.onFetchStatus(statusId)
|
||||
}
|
||||
|
||||
export default class Status extends PureComponent {
|
||||
render() {
|
||||
const { status } = this.props
|
||||
|
||||
// - if comment render as such
|
||||
|
||||
if (!status) {
|
||||
return <ColumnIndicator type='loading' />
|
||||
}
|
||||
|
||||
return (
|
||||
<StatusContainer {...this.props} />
|
||||
)
|
||||
|
||||
@@ -1,72 +1,70 @@
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
import { FormattedMessage } from 'react-intl'
|
||||
import { fetchLikes } from '../actions/interactions'
|
||||
import { fetchStatus } from '../actions/statuses'
|
||||
import { makeGetStatus } from '../selectors'
|
||||
import Account from '../components/account'
|
||||
import ColumnIndicator from '../components/column_indicator'
|
||||
import ScrollableList from '../components/scrollable_list'
|
||||
|
||||
const messages = defineMessages({
|
||||
refresh: { id: 'refresh', defaultMessage: 'Refresh' },
|
||||
});
|
||||
const mapStateToProps = (state, props) => {
|
||||
const getStatus = makeGetStatus()
|
||||
const status = getStatus(state, {
|
||||
id: props.params.statusId,
|
||||
username: props.params.username,
|
||||
})
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
accountIds: state.getIn(['user_lists', 'favourited_by', props.params.statusId]),
|
||||
});
|
||||
return {
|
||||
status,
|
||||
accountIds: state.getIn(['user_lists', 'liked_by', props.params.statusId]),
|
||||
}
|
||||
}
|
||||
|
||||
export default
|
||||
@injectIntl
|
||||
@connect(mapStateToProps)
|
||||
class StatusLikes extends ImmutablePureComponent {
|
||||
class StatusReposts extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
shouldUpdateScroll: PropTypes.func,
|
||||
accountIds: ImmutablePropTypes.list,
|
||||
multiColumn: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
status: ImmutablePropTypes.map,
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
if (!this.props.accountIds) {
|
||||
this.props.dispatch(fetchLikes(this.props.params.statusId));
|
||||
}
|
||||
this.props.dispatch(fetchLikes(this.props.params.statusId))
|
||||
this.props.dispatch(fetchStatus(this.props.params.statusId))
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
|
||||
this.props.dispatch(fetchLikes(nextProps.params.statusId));
|
||||
this.props.dispatch(fetchLikes(nextProps.params.statusId))
|
||||
this.props.dispatch(fetchStatus(nextProps.params.statusId))
|
||||
}
|
||||
}
|
||||
|
||||
handleRefresh = () => {
|
||||
this.props.dispatch(fetchLikes(this.props.params.statusId));
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, shouldUpdateScroll, accountIds, multiColumn } = this.props;
|
||||
const { accountIds, status } = this.props
|
||||
|
||||
if (!accountIds) {
|
||||
return <ColumnIndicator type='loading' />
|
||||
} else if (!status) {
|
||||
return <ColumnIndicator type='missing' />
|
||||
}
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.favourites' defaultMessage='No one has favourited this toot yet. When someone does, they will show up here.' />;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ScrollableList
|
||||
scrollKey='favourites'
|
||||
shouldUpdateScroll={shouldUpdateScroll}
|
||||
emptyMessage={emptyMessage}
|
||||
bindToDocument={!multiColumn}
|
||||
>
|
||||
{accountIds.map(id =>
|
||||
<Account key={id} id={id} withNote={false} />,
|
||||
)}
|
||||
</ScrollableList>
|
||||
</div>
|
||||
);
|
||||
<ScrollableList
|
||||
scrollKey='likes'
|
||||
emptyMessage={<FormattedMessage id='status.likes.empty' defaultMessage='No one has liked this gab yet. When someone does, they will show up here.' />}
|
||||
>
|
||||
{
|
||||
accountIds.map(id =>
|
||||
<Account key={id} id={id} />
|
||||
)
|
||||
}
|
||||
</ScrollableList>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ class SwitchingArea extends PureComponent {
|
||||
<Redirect from='/' to='/home' exact />
|
||||
<WrappedRoute path='/home' exact page={HomePage} component={HomeTimeline} content={children} />
|
||||
|
||||
<WrappedRoute path='/timeline/all' exact page={CommunityPage} component={CommunityTimeline} content={children} componentParams={{ title: 'Community Timeline' }} />
|
||||
<WrappedRoute path='/timeline/all' exact page={CommunityPage} component={CommunityTimeline} content={children} componentParams={{ title: 'Community Feed' }} />
|
||||
|
||||
<WrappedRoute path='/groups' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'featured' }} />
|
||||
<WrappedRoute path='/groups/new' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'new' }} />
|
||||
|
||||
@@ -65,6 +65,8 @@ export function SidebarMorePopover() { return import(/* webpackChunkName: "compo
|
||||
export function StatusLikes() { return import(/* webpackChunkName: "features/status_likes" */'../../status_likes') }
|
||||
export function StatusOptionsPopover() { return import(/* webpackChunkName: "components/status_options_popover" */'../../../components/popover/status_options_popover') }
|
||||
export function StatusReposts() { return import(/* webpackChunkName: "features/status_reposts" */'../../status_reposts') }
|
||||
export function StatusLikesModal() { return import(/* webpackChunkName: "modals/status_likes_modal" */'../../../components/modal/status_likes_modal') }
|
||||
export function StatusRepostsModal() { return import(/* webpackChunkName: "modals/status_reposts_modal" */'../../../components/modal/status_reposts_modal') }
|
||||
export function StatusRevisionsModal() { return import(/* webpackChunkName: "modals/status_revisions_modal" */'../../../components/modal/status_revisions_modal') }
|
||||
export function StatusSharePopover() { return import(/* webpackChunkName: "components/status_share_popover" */'../../../components/popover/status_share_popover') }
|
||||
export function StatusVisibilityPopover() { return import(/* webpackChunkName: "components/status_visibility_popover" */'../../../components/popover/status_visibility_popover') }
|
||||
|
||||
Reference in New Issue
Block a user