From 4ba2d0816237c2fa6f3ae1565e5e9e12d18b635f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 2 Jun 2022 20:51:09 +0200 Subject: [PATCH] Lists modals: TypeScript, FC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../features/list_adder/components/account.js | 44 -------- .../list_adder/components/account.tsx | 31 ++++++ .../features/list_adder/components/list.js | 70 ------------ .../features/list_adder/components/list.tsx | 49 ++++++++ app/soapbox/features/list_adder/index.js | 105 ------------------ app/soapbox/features/list_adder/index.tsx | 83 ++++++++++++++ .../list_editor/components/account.js | 78 ------------- .../list_editor/components/account.tsx | 58 ++++++++++ .../list_editor/components/edit_list_form.js | 73 ------------ .../list_editor/components/edit_list_form.tsx | 53 +++++++++ .../features/list_editor/components/search.js | 83 -------------- .../list_editor/components/search.tsx | 58 ++++++++++ app/soapbox/features/list_editor/index.js | 105 ------------------ app/soapbox/features/list_editor/index.tsx | 79 +++++++++++++ app/soapbox/features/list_timeline/index.tsx | 2 +- .../lists/components/new_list_form.tsx | 43 +++---- app/soapbox/features/lists/index.tsx | 8 +- .../components/color-picker.tsx | 2 +- app/soapbox/types/entities.ts | 3 + app/styles/application.scss | 1 - app/styles/components/list-forms.scss | 105 ------------------ app/styles/components/modal.scss | 27 ----- app/styles/components/search.scss | 10 -- 23 files changed, 442 insertions(+), 728 deletions(-) delete mode 100644 app/soapbox/features/list_adder/components/account.js create mode 100644 app/soapbox/features/list_adder/components/account.tsx delete mode 100644 app/soapbox/features/list_adder/components/list.js create mode 100644 app/soapbox/features/list_adder/components/list.tsx delete mode 100644 app/soapbox/features/list_adder/index.js create mode 100644 app/soapbox/features/list_adder/index.tsx delete mode 100644 app/soapbox/features/list_editor/components/account.js create mode 100644 app/soapbox/features/list_editor/components/account.tsx delete mode 100644 app/soapbox/features/list_editor/components/edit_list_form.js create mode 100644 app/soapbox/features/list_editor/components/edit_list_form.tsx delete mode 100644 app/soapbox/features/list_editor/components/search.js create mode 100644 app/soapbox/features/list_editor/components/search.tsx delete mode 100644 app/soapbox/features/list_editor/index.js create mode 100644 app/soapbox/features/list_editor/index.tsx delete mode 100644 app/styles/components/list-forms.scss diff --git a/app/soapbox/features/list_adder/components/account.js b/app/soapbox/features/list_adder/components/account.js deleted file mode 100644 index 184339572..000000000 --- a/app/soapbox/features/list_adder/components/account.js +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { injectIntl } from 'react-intl'; -import { connect } from 'react-redux'; - -import Avatar from '../../../components/avatar'; -import DisplayName from '../../../components/display-name'; -import { makeGetAccount } from '../../../selectors'; - -const makeMapStateToProps = () => { - const getAccount = makeGetAccount(); - - const mapStateToProps = (state, { accountId }) => ({ - account: getAccount(state, accountId), - }); - - return mapStateToProps; -}; - - -export default @connect(makeMapStateToProps) -@injectIntl -class Account extends ImmutablePureComponent { - - static propTypes = { - account: ImmutablePropTypes.record.isRequired, - }; - - render() { - const { account } = this.props; - return ( -
-
-
-
- -
-
-
- ); - } - -} diff --git a/app/soapbox/features/list_adder/components/account.tsx b/app/soapbox/features/list_adder/components/account.tsx new file mode 100644 index 000000000..304b32207 --- /dev/null +++ b/app/soapbox/features/list_adder/components/account.tsx @@ -0,0 +1,31 @@ +import React from 'react'; + +import DisplayName from 'soapbox/components/display-name'; +import { Avatar } from 'soapbox/components/ui'; +import { useAppSelector } from 'soapbox/hooks'; +import { makeGetAccount } from 'soapbox/selectors'; + +const getAccount = makeGetAccount(); + +interface IAccount { + accountId: string, +} + +const Account: React.FC = ({ accountId }) => { + const account = useAppSelector((state) => getAccount(state, accountId)); + + if (!account) return null; + + return ( +
+
+
+
+ +
+
+
+ ); +}; + +export default Account; diff --git a/app/soapbox/features/list_adder/components/list.js b/app/soapbox/features/list_adder/components/list.js deleted file mode 100644 index fd9930180..000000000 --- a/app/soapbox/features/list_adder/components/list.js +++ /dev/null @@ -1,70 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl } from 'react-intl'; -import { connect } from 'react-redux'; - -import { removeFromListAdder, addToListAdder } from 'soapbox/actions/lists'; -import Icon from 'soapbox/components/icon'; -import IconButton from 'soapbox/components/icon_button'; - -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)), -}); - -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; - - let button; - - if (added) { - button = ; - } else { - button = ; - } - - return ( -
-
-
- - {list.get('title')} -
- -
- {button} -
-
-
- ); - } - -} diff --git a/app/soapbox/features/list_adder/components/list.tsx b/app/soapbox/features/list_adder/components/list.tsx new file mode 100644 index 000000000..822833476 --- /dev/null +++ b/app/soapbox/features/list_adder/components/list.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { defineMessages, useIntl } from 'react-intl'; + +import { removeFromListAdder, addToListAdder } from 'soapbox/actions/lists'; +import Icon from 'soapbox/components/icon'; +import IconButton from 'soapbox/components/icon_button'; +import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; + +const messages = defineMessages({ + remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' }, + add: { id: 'lists.account.add', defaultMessage: 'Add to list' }, +}); + +interface IList { + listId: string, +} + +const List: React.FC = ({ listId }) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + const list = useAppSelector((state) => state.lists.get(listId)); + const added = useAppSelector((state) => state.listAdder.lists.items.includes(listId)); + + const onRemove = () => dispatch(removeFromListAdder(listId)); + const onAdd = () => dispatch(addToListAdder(listId)); + + if (!list) return null; + + let button; + + if (added) { + button = ; + } else { + button = ; + } + + return ( +
+ + + {list.title} + + {button} +
+ ); +}; + +export default List; diff --git a/app/soapbox/features/list_adder/index.js b/app/soapbox/features/list_adder/index.js deleted file mode 100644 index 7b7a6fb55..000000000 --- a/app/soapbox/features/list_adder/index.js +++ /dev/null @@ -1,105 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; - -import { setupListAdder, resetListAdder } from 'soapbox/actions/lists'; -import { CardHeader, CardTitle, Modal } from 'soapbox/components/ui'; - -import NewListForm from '../lists/components/new_list_form'; - -import Account from './components/account'; -import List from './components/list'; - -// hack -const getOrderedLists = createSelector([state => state.get('lists')], lists => { - if (!lists) { - return lists; - } - - return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title'))); -}); - -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' }, -}); - -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.record, - }; - - componentDidMount() { - const { onInitialize, accountId } = this.props; - onInitialize(accountId); - } - - componentWillUnmount() { - const { onReset } = this.props; - onReset(); - } - - onClickClose = () => { - this.props.onClose('LIST_ADDER'); - }; - - render() { - const { accountId, listIds, intl } = this.props; - - return ( - } - onClose={this.onClickClose} - > -
-
-
- -
- -
- - - - - - -
- - - - -
- {listIds.map(ListId => )} -
-
-
-
- ); - } - -} diff --git a/app/soapbox/features/list_adder/index.tsx b/app/soapbox/features/list_adder/index.tsx new file mode 100644 index 000000000..10d706519 --- /dev/null +++ b/app/soapbox/features/list_adder/index.tsx @@ -0,0 +1,83 @@ +import React from 'react'; +import { useEffect } from 'react'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; +import { createSelector } from 'reselect'; + +import { setupListAdder, resetListAdder } from 'soapbox/actions/lists'; +import { CardHeader, CardTitle, Modal } from 'soapbox/components/ui'; +import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; + +import NewListForm from '../lists/components/new_list_form'; + +import Account from './components/account'; +import List from './components/list'; + +import type { List as ImmutableList } from 'immutable'; +import type { RootState } from 'soapbox/store'; +import type { List as ListEntity } from 'soapbox/types/entities'; + +const messages = defineMessages({ + close: { id: 'lightbox.close', defaultMessage: 'Close' }, + subheading: { id: 'lists.subheading', defaultMessage: 'Your lists' }, + add: { id: 'lists.new.create', defaultMessage: 'Add List' }, +}); + +// hack +const getOrderedLists = createSelector([(state: RootState) => state.lists], lists => { + if (!lists) { + return lists; + } + + return lists.toList().filter(item => !!item).sort((a, b) => (a as ListEntity).title.localeCompare((b as ListEntity).title)) as ImmutableList; +}); + +interface IListAdder { + accountId: string, + onClose: (type: string) => void, +} + +const ListAdder: React.FC = ({ accountId, onClose }) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + const listIds = useAppSelector((state) => getOrderedLists(state).map(list => list.id)); + + useEffect(() => { + dispatch(setupListAdder(accountId)); + + return () => { + dispatch(resetListAdder()); + }; + }, []); + + const onClickClose = () => { + onClose('LIST_ADDER'); + }; + + return ( + } + onClose={onClickClose} + > + + +
+ + + + + + +
+ + + + +
+ {listIds.map(ListId => )} +
+
+ ); +}; + +export default ListAdder; diff --git a/app/soapbox/features/list_editor/components/account.js b/app/soapbox/features/list_editor/components/account.js deleted file mode 100644 index e73a465ca..000000000 --- a/app/soapbox/features/list_editor/components/account.js +++ /dev/null @@ -1,78 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl } from 'react-intl'; -import { connect } from 'react-redux'; - -import { removeFromListEditor, addToListEditor } from '../../../actions/lists'; -import Avatar from '../../../components/avatar'; -import DisplayName from '../../../components/display-name'; -import IconButton from '../../../components/icon_button'; -import { makeGetAccount } from '../../../selectors'; - -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.record.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 = ; - } else { - button = ; - } - - return ( -
-
-
-
- -
- -
- {button} -
-
-
- ); - } - -} diff --git a/app/soapbox/features/list_editor/components/account.tsx b/app/soapbox/features/list_editor/components/account.tsx new file mode 100644 index 000000000..f3c52d9f3 --- /dev/null +++ b/app/soapbox/features/list_editor/components/account.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { defineMessages, useIntl } from 'react-intl'; + +import { removeFromListEditor, addToListEditor } from 'soapbox/actions/lists'; +import DisplayName from 'soapbox/components/display-name'; +import IconButton from 'soapbox/components/icon_button'; +import { Avatar } from 'soapbox/components/ui'; +import { useAppSelector, useAppDispatch } from 'soapbox/hooks'; +import { makeGetAccount } from 'soapbox/selectors'; + +const messages = defineMessages({ + remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' }, + add: { id: 'lists.account.add', defaultMessage: 'Add to list' }, +}); + +const getAccount = makeGetAccount(); + +interface IAccount { + accountId: string, +} + +const Account: React.FC = ({ accountId }) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + const account = useAppSelector((state) => getAccount(state, accountId)); + const isAdded = useAppSelector((state) => state.listEditor.accounts.items.includes(accountId)); + + const onRemove = () => dispatch(removeFromListEditor(accountId)); + const onAdd = () => dispatch(addToListEditor(accountId)); + + if (!account) return null; + + let button; + + if (isAdded) { + button = ; + } else { + button = ; + } + + return ( +
+
+
+
+ +
+ +
+ {button} +
+
+
+ ); +}; + +export default Account; diff --git a/app/soapbox/features/list_editor/components/edit_list_form.js b/app/soapbox/features/list_editor/components/edit_list_form.js deleted file mode 100644 index 0553172d1..000000000 --- a/app/soapbox/features/list_editor/components/edit_list_form.js +++ /dev/null @@ -1,73 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import { defineMessages, injectIntl } from 'react-intl'; -import { connect } from 'react-redux'; - -import { changeListEditorTitle, submitListEditor } from '../../../actions/lists'; -import { Button } from '../../../components/ui'; - -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 React.PureComponent { - - static propTypes = { - value: PropTypes.string.isRequired, - disabled: PropTypes.bool, - intl: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - }; - - handleChange = e => { - this.props.onChange(e.target.value); - } - - handleSubmit = e => { - e.preventDefault(); - this.props.onSubmit(); - } - - handleClick = () => { - this.props.onSubmit(); - } - - render() { - const { value, disabled, intl } = this.props; - const save = intl.formatMessage(messages.save); - - return ( -
- - - { !disabled && - - } -
- ); - } - -} diff --git a/app/soapbox/features/list_editor/components/edit_list_form.tsx b/app/soapbox/features/list_editor/components/edit_list_form.tsx new file mode 100644 index 000000000..ba365e40b --- /dev/null +++ b/app/soapbox/features/list_editor/components/edit_list_form.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { defineMessages, useIntl } from 'react-intl'; + +import { changeListEditorTitle, submitListEditor } from 'soapbox/actions/lists'; +import { Button, Form, HStack, Input } from 'soapbox/components/ui'; +import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; + +const messages = defineMessages({ + title: { id: 'lists.edit.submit', defaultMessage: 'Change title' }, + save: { id: 'lists.new.save_title', defaultMessage: 'Save Title' }, +}); + +const ListForm = () => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + const value = useAppSelector((state) => state.listEditor.title); + const disabled = useAppSelector((state) => !state.listEditor.isChanged); + + const handleChange: React.ChangeEventHandler = e => { + dispatch(changeListEditorTitle(e.target.value)); + }; + + const handleSubmit: React.FormEventHandler = e => { + e.preventDefault(); + dispatch(submitListEditor(false)); + }; + + const handleClick = () => { + dispatch(submitListEditor(false)); + }; + + const save = intl.formatMessage(messages.save); + + return ( +
+ + + + + +
+ ); +}; + +export default ListForm; diff --git a/app/soapbox/features/list_editor/components/search.js b/app/soapbox/features/list_editor/components/search.js deleted file mode 100644 index 3314fa4e3..000000000 --- a/app/soapbox/features/list_editor/components/search.js +++ /dev/null @@ -1,83 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { defineMessages, injectIntl } from 'react-intl'; -import { connect } from 'react-redux'; - -import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from 'soapbox/actions/lists'; -import Icon from 'soapbox/components/icon'; -import { Button } from 'soapbox/components/ui'; - -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 Search extends React.PureComponent { - - static propTypes = { - intl: PropTypes.object.isRequired, - value: PropTypes.string.isRequired, - onChange: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onClear: PropTypes.func.isRequired, - }; - - handleChange = e => { - this.props.onChange(e.target.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; - const hasValue = value.length > 0; - - return ( -
- - -
- -
- -
- ); - } - -} diff --git a/app/soapbox/features/list_editor/components/search.tsx b/app/soapbox/features/list_editor/components/search.tsx new file mode 100644 index 000000000..edd78250f --- /dev/null +++ b/app/soapbox/features/list_editor/components/search.tsx @@ -0,0 +1,58 @@ +import classNames from 'classnames'; +import React from 'react'; +import { defineMessages, useIntl } from 'react-intl'; + +import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from 'soapbox/actions/lists'; +import Icon from 'soapbox/components/icon'; +import { Button, Form, HStack, Input } from 'soapbox/components/ui'; +import { useAppSelector, useAppDispatch } from 'soapbox/hooks'; + +const messages = defineMessages({ + search: { id: 'lists.search', defaultMessage: 'Search among people you follow' }, + searchTitle: { id: 'tabs_bar.search', defaultMessage: 'Search' }, +}); + +const Search = () => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + const value = useAppSelector((state) => state.listEditor.suggestions.value); + + const handleChange: React.ChangeEventHandler = e => { + dispatch(changeListSuggestions(e.target.value)); + }; + + const handleSubmit = () => { + dispatch(fetchListSuggestions(value)); + }; + + const handleClear = () => { + dispatch(clearListSuggestions()); + }; + + const hasValue = value.length > 0; + + return ( +
+ + + + + +
+ ); +}; + +export default Search; diff --git a/app/soapbox/features/list_editor/index.js b/app/soapbox/features/list_editor/index.js deleted file mode 100644 index 82c943d21..000000000 --- a/app/soapbox/features/list_editor/index.js +++ /dev/null @@ -1,105 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { injectIntl, defineMessages, FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; - -import { setupListEditor, clearListSuggestions, resetListEditor } from 'soapbox/actions/lists'; -import { CardHeader, CardTitle, Modal } from 'soapbox/components/ui'; - -import Account from './components/account'; -import EditListForm from './components/edit_list_form'; -import Search from './components/search'; - -const mapStateToProps = state => ({ - accountIds: state.getIn(['listEditor', 'accounts', 'items']), - searchAccountIds: state.getIn(['listEditor', 'suggestions', 'items']), -}); - -const mapDispatchToProps = dispatch => ({ - onInitialize: listId => dispatch(setupListEditor(listId)), - onClear: () => dispatch(clearListSuggestions()), - 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' }, -}); - -export default @connect(mapStateToProps, mapDispatchToProps) -@injectIntl -class ListEditor extends ImmutablePureComponent { - - static propTypes = { - listId: PropTypes.string.isRequired, - onClose: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - onInitialize: PropTypes.func.isRequired, - onClear: PropTypes.func.isRequired, - onReset: PropTypes.func.isRequired, - accountIds: ImmutablePropTypes.list.isRequired, - searchAccountIds: ImmutablePropTypes.list.isRequired, - }; - - componentDidMount() { - const { onInitialize, listId } = this.props; - onInitialize(listId); - } - - componentWillUnmount() { - const { onReset } = this.props; - onReset(); - } - - onClickClose = () => { - this.props.onClose('LIST_ADDER'); - }; - - render() { - const { accountIds, searchAccountIds, intl } = this.props; - - return ( - } - onClose={this.onClickClose} - > -
-
- - - - -
- - { - accountIds.size > 0 && -
- - - -
- {accountIds.map(accountId => )} -
-
- } - -
- - - - -
- {searchAccountIds.map(accountId => )} -
-
-
-
- ); - } - -} diff --git a/app/soapbox/features/list_editor/index.tsx b/app/soapbox/features/list_editor/index.tsx new file mode 100644 index 000000000..d495f4b2f --- /dev/null +++ b/app/soapbox/features/list_editor/index.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import { useEffect } from 'react'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import { setupListEditor, resetListEditor } from 'soapbox/actions/lists'; +import { CardHeader, CardTitle, Modal } from 'soapbox/components/ui'; +import { useAppSelector, useAppDispatch } from 'soapbox/hooks'; + +import Account from './components/account'; +import EditListForm from './components/edit_list_form'; +import Search from './components/search'; + +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' }, +}); + +interface IListEditor { + listId: string, + onClose: (type: string) => void, +} + +const ListEditor: React.FC = ({ listId, onClose }) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + const accountIds = useAppSelector((state) => state.listEditor.accounts.items); + const searchAccountIds = useAppSelector((state) => state.listEditor.suggestions.items); + + useEffect(() => { + dispatch(setupListEditor(listId)); + + return () => { + dispatch(resetListEditor()); + }; + }, []); + + const onClickClose = () => { + onClose('LIST_ADDER'); + }; + + return ( + } + onClose={onClickClose} + > + + + + +
+ + {accountIds.size > 0 && ( +
+ + + +
+ {accountIds.map(accountId => )} +
+
+ )} + +
+ + + + +
+ {searchAccountIds.map(accountId => )} +
+
+ ); +}; + +export default ListEditor; diff --git a/app/soapbox/features/list_timeline/index.tsx b/app/soapbox/features/list_timeline/index.tsx index 85441c98f..9402de86a 100644 --- a/app/soapbox/features/list_timeline/index.tsx +++ b/app/soapbox/features/list_timeline/index.tsx @@ -65,7 +65,7 @@ const ListTimeline: React.FC = () => { // })); // }; - const title = list ? list.get('title') : id; + const title = list ? list.title : id; if (typeof list === 'undefined') { return ( diff --git a/app/soapbox/features/lists/components/new_list_form.tsx b/app/soapbox/features/lists/components/new_list_form.tsx index b6385ecf3..eb19d1e87 100644 --- a/app/soapbox/features/lists/components/new_list_form.tsx +++ b/app/soapbox/features/lists/components/new_list_form.tsx @@ -3,7 +3,7 @@ import { defineMessages, useIntl } from 'react-intl'; import { useDispatch } from 'react-redux'; import { changeListEditorTitle, submitListEditor } from 'soapbox/actions/lists'; -import { Button } from 'soapbox/components/ui'; +import { Button, Form, HStack, Input } from 'soapbox/components/ui'; import { useAppSelector } from 'soapbox/hooks'; const messages = defineMessages({ @@ -23,7 +23,7 @@ const NewListForm: React.FC = () => { dispatch(changeListEditorTitle(e.target.value)); }; - const handleSubmit = (e: React.FormEvent) => { + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); dispatch(submitListEditor(true)); }; @@ -32,27 +32,28 @@ const NewListForm: React.FC = () => { const create = intl.formatMessage(messages.create); return ( -
-