@ -4,16 +4,49 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component' ;
import PropTypes from 'prop-types' ;
import Column from '../ui/components/column' ;
import { fetchFilters } from '../../actions/filters' ;
import { fetchFilters , createFilter } from '../../actions/filters' ;
import ScrollableList from '../../components/scrollable_list' ;
import Button from 'soapbox/components/button' ;
import {
SimpleForm ,
SimpleInput ,
FieldsGroup ,
TextInput ,
SelectDropdown ,
Checkbox ,
} from 'soapbox/features/forms' ;
import { showAlert } from 'soapbox/actions/alerts' ;
const messages = defineMessages ( {
heading : { id : 'column.filters' , defaultMessage : 'Muted words' } ,
keyword : { id : 'column.filters.keyword' , defaultMessage : 'Keyword or phrase' } ,
expires : { id : 'column.filters.expires' , defaultMessage : 'Expire after' } ,
home _timeline : { id : 'column.filters.home_timeline' , defaultMessage : 'Home timeline' } ,
public _timeline : { id : 'column.filters.public_timeline' , defaultMessage : 'Public timeline' } ,
notifications : { id : 'column.filters.notifications' , defaultMessage : 'Notifications' } ,
conversations : { id : 'column.filters.conversations' , defaultMessage : 'Conversations' } ,
drop _header : { id : 'column.filters.drop_header' , defaultMessage : 'Drop instead of hide' } ,
drop _hint : { id : 'column.filters.drop_hint' , defaultMessage : 'Filtered posts will disappear irreversibly, even if filter is later removed' } ,
whole _word _header : { id : 'column.filters.whole_word_header' , defaultMessage : 'Whole word' } ,
whole _word _hint : { id : 'column.filters.whole_word_hint' , defaultMessage : 'When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word' } ,
add _new : { id : 'column.filters.add_new' , defaultMessage : 'Add New Muted Word' } ,
error : { id : 'column.filters.error' , defaultMessage : 'Error adding filter' } ,
} ) ;
const expirations = {
1800 : 'Never' ,
3600 : '30 minutes' ,
21600 : '1 hour' ,
43200 : '12 hours' ,
86400 : '1 day' ,
604800 : '1 week' ,
} ;
const mapStateToProps = state => ( {
filters : state . get ( 'filters' ) ,
} ) ;
export default @ connect ( mapStateToProps )
@ injectIntl
class Filters extends ImmutablePureComponent {
@ -24,17 +57,152 @@ class Filters extends ImmutablePureComponent {
intl : PropTypes . object . isRequired ,
} ;
state = {
phrase : '' ,
expires _at : '' ,
context : {
home _timeline : false ,
public _timeline : false ,
notifications : false ,
conversations : false ,
} ,
irreversible : false ,
whole _word : true ,
}
componentDidMount ( ) {
this . props . dispatch ( fetchFilters ( ) ) ;
}
handleInputChange = e => {
this . setState ( { [ e . target . name ] : e . target . value } ) ;
}
handleSelectChange = e => {
this . setState ( { [ e . target . name ] : e . target . value } ) ;
}
handleCheckboxChange = e => {
this . setState ( { [ e . target . name ] : e . target . checked } ) ;
}
handleAddNew = e => {
e . preventDefault ( ) ;
const { intl , dispatch } = this . state ;
const { phrase , context , whole _word , expires _at } = this . state ;
dispatch ( createFilter ( phrase , context , whole _word , expires _at ) ) . then ( response => {
dispatch ( fetchFilters ( ) ) ;
} ) . catch ( error => {
dispatch ( showAlert ( '' , intl . formatMessage ( messages . error ) ) ) ;
} ) ;
}
render ( ) {
const { intl } = this . props ;
const { intl , filters } = this . props ;
const emptyMessage = < FormattedMessage id = 'empty_column.filters' defaultMessage = "You haven't created any muted words yet." / > ;
return (
< Column icon = 'filter' heading = { intl . formatMessage ( messages . heading ) } backBtnSlim >
{ emptyMessage }
< SimpleForm >
< div className = 'filter-settings-panel' >
< h1 className = 'filter-settings-panel__add-new' >
< FormattedMessage id = 'filters.add_new_title' defaultMessage = 'Add New Filter' / >
< / h 1 >
< fieldset disabled = { false } >
< FieldsGroup >
< SimpleInput
label = { intl . formatMessage ( messages . keyword ) }
required
type = 'text'
name = 'custom_filter_phrase'
onChange = { this . handleInputChange }
/ >
< SelectDropdown
label = { intl . formatMessage ( messages . expires ) }
items = { expirations }
defaultValue = { expirations . never }
onChange = { this . handleSelectChange }
/ >
< / F i e l d s G r o u p >
< FieldsGroup >
< label className = 'checkboxes required' >
< FormattedMessage id = 'filters.context_header' defaultMessage = 'Filter contexts' / >
< / l a b e l >
< span className = 'hint' >
< FormattedMessage id = 'filters.context_hint' defaultMessage = 'One or multiple contexts where the filter should apply' / >
< / s p a n >
< Checkbox
label = { intl . formatMessage ( messages . home _timeline ) }
name = 'home_timeline'
checked = { this . state . context . home _timeline }
onChange = { this . handleCheckboxChange }
/ >
< Checkbox
label = { intl . formatMessage ( messages . public _timeline ) }
name = 'public_timeline'
checked = { this . state . context . public _timeline }
onChange = { this . handleCheckboxChange }
/ >
< Checkbox
label = { intl . formatMessage ( messages . notifications ) }
name = 'notifications'
checked = { this . state . context . notifications }
onChange = { this . handleCheckboxChange }
/ >
< Checkbox
label = { intl . formatMessage ( messages . conversations ) }
name = 'conversations'
checked = { this . state . context . conversations }
onChange = { this . handleCheckboxChange }
/ >
< / F i e l d s G r o u p >
< FieldsGroup >
< Checkbox
label = { intl . formatMessage ( messages . drop _header ) }
hint = { intl . formatMessage ( messages . drop _hint ) }
name = 'irreversible'
checked = { this . state . irreversible }
onChange = { this . handleCheckboxChange }
/ >
< Checkbox
label = { intl . formatMessage ( messages . whole _word _header ) }
hint = { intl . formatMessage ( messages . whole _word _hint ) }
name = 'whole_word'
checked = { this . state . whole _word }
onChange = { this . handleCheckboxChange }
/ >
< / F i e l d s G r o u p >
< / f i e l d s e t >
< Button className = 'button button-primary setup' text = { intl . formatMessage ( messages . add _new ) } onClick = { this . props . handleAddNew } / >
< ScrollableList
scrollKey = 'mutes'
onLoadMore = { this . handleLoadMore }
emptyMessage = { emptyMessage }
>
{ filters . map ( ( filter , i ) => (
< div key = { i } className = 'backup_code' >
< div className = 'backup_code' > { filter } < / d i v >
< / d i v >
) ) }
< / S c r o l l a b l e L i s t >
< / d i v >
< / S i m p l e F o r m >
< / C o l u m n >
) ;
}