Commit aa3e3701 authored by Roger Jungemann's avatar Roger Jungemann
Browse files

Remove most follower/following code

parent beea5deb
......@@ -2,10 +2,9 @@ import GDPRUserList from './utils/GDPRUserList';
export const routeRegex = {
UserProfile1: /^\/(@[\w\.\d-]+)\/?$/,
UserProfile2: /^\/(@[\w\.\d-]+)\/(transfers|permissions|created|password|followed|followers|settings)\/?$/,
UserProfile2: /^\/(@[\w\.\d-]+)\/(transfers|permissions|password|settings)\/?$/,
UserProfile3: /^\/(@[\w\.\d-]+)\/[\w\.\d-]+/,
UserEndPoints: /^(transfers|permissions|created|password|followed|followers|settings)$/,
CategoryFilters: /^\/(cashout|payout|payout_comments|created|active)\/?$/gi,
UserEndPoints: /^(transfers|permissions|password|settings)$/,
};
export default function resolveRoute(path) {
......@@ -71,13 +70,5 @@ export default function resolveRoute(path) {
}
return { page: 'UserProfile', params: match.slice(1) };
}
match =
path.match(/^\/(cashout|payout|payout_comments|created|active)\/?$/) ||
path.match(
/^\/(cashout|payout|payout_comments|created|active)\/([\w\d-]+)\/?$/
);
if (match) {
return { page: 'WalletIndex', params: match.slice(1) };
}
return { page: 'NotFound' };
}
......@@ -7,13 +7,9 @@ describe('routeRegex', () => {
['UserProfile1', /^\/(@[\w\.\d-]+)\/?$/],
[
'UserProfile2',
/^\/(@[\w\.\d-]+)\/(transfers|permissions|created|password|followed|followers|settings)\/?$/,
/^\/(@[\w\.\d-]+)\/(transfers|permissions|password|settings)\/?$/,
],
['UserProfile3', /^\/(@[\w\.\d-]+)\/[\w\.\d-]+/],
[
'CategoryFilters',
/^\/(cashout|payout|payout_comments|created|active)\/?$/gi,
],
];
test_cases.forEach(r => {
......
import React from 'react';
import { Link } from 'react-router';
import Follow from 'app/components/elements/Follow';
class UserListRow extends React.Component {
render() {
const { user, loggedIn } = this.props;
return (
<tr>
{loggedIn && (
<td width="250">
<Follow following={user} />
</td>
)}
<td>
<Link to={'/@' + user}>
<strong>{user}</strong>
......
import React from 'react';
import { storiesOf } from '@storybook/react';
import { withKnobs, boolean } from '@storybook/addon-knobs';
import rootReducer from 'app/redux/RootReducer';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import Follow from './index';
import { Center } from 'decorators';
const store = createStore(rootReducer);
storiesOf('Elements', module)
.addDecorator(withKnobs)
.addDecorator(Center)
.addDecorator(getStory => <Provider store={store}>{getStory()}</Provider>)
.add('Follow', () => (
<Follow
className="float-right"
follower={'maitland'}
following={'Carol'}
what="blog"
showFollow={boolean('Show Follow?', true)}
showMute={boolean('Show Mute?', true)}
/>
));
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Follow /> renders without crashing 1`] = `
ShallowWrapper {
"length": 1,
Symbol(enzyme.__root__): [Circular],
Symbol(enzyme.__unrendered__): <Provider
store={
Object {
"dispatch": [Function],
"getState": [Function],
"replaceReducer": [Function],
"subscribe": [Function],
Symbol(observable): [Function],
}
}
>
<Connect(Follow) />
</Provider>,
Symbol(enzyme.__renderer__): Object {
"batchedUpdates": [Function],
"getNode": [Function],
"render": [Function],
"simulateEvent": [Function],
"unmount": [Function],
},
Symbol(enzyme.__node__): Object {
"instance": null,
"key": undefined,
"nodeType": "class",
"props": Object {},
"ref": null,
"rendered": null,
"type": [Function],
},
Symbol(enzyme.__nodes__): Array [
Object {
"instance": null,
"key": undefined,
"nodeType": "class",
"props": Object {},
"ref": null,
"rendered": null,
"type": [Function],
},
],
Symbol(enzyme.__options__): Object {
"adapter": ReactFifteenAdapter {
"options": Object {
"supportPrevContextArgumentOfComponentDidUpdate": true,
},
},
},
}
`;
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import LoadingIndicator from 'app/components/elements/LoadingIndicator';
import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
import * as transactionActions from 'app/redux/TransactionReducer';
import * as userActions from 'app/redux/UserReducer';
import { Set, Map } from 'immutable';
import tt from 'counterpart';
const { string, bool, any } = PropTypes;
export default class Follow extends React.Component {
static propTypes = {
following: string,
follower: string, // OPTIONAL default to current user
showFollow: bool,
showMute: bool,
fat: bool,
children: any,
showLogin: PropTypes.func.isRequired,
};
static defaultProps = {
showFollow: true,
showMute: true,
fat: false,
};
constructor(props) {
super();
this.state = {};
this.initEvents(props);
this.followLoggedOut = this.followLoggedOut.bind(this);
this.shouldComponentUpdate = shouldComponentUpdate(this, 'Follow');
}
componentWillUpdate(nextProps) {
this.initEvents(nextProps);
}
initEvents(props) {
const { updateFollow, follower, following } = props;
const upd = type => {
if (this.state.busy) return;
this.setState({ busy: true });
const done = () => {
this.setState({ busy: false });
};
updateFollow(follower, following, type, done);
};
this.follow = () => {
upd('blog');
};
this.unfollow = () => {
upd();
};
this.ignore = () => {
upd('ignore');
};
this.unignore = () => {
upd();
};
}
followLoggedOut(e) {
// close author preview if present
const author_preview = document.querySelector('.dropdown-pane.is-open');
if (author_preview) author_preview.remove();
// resume authenticate modal
this.props.showLogin(e);
}
render() {
const { loading } = this.props;
if (loading)
return (
<span>
<LoadingIndicator /> {tt('g.loading')}&hellip;
</span>
);
if (loading !== false) {
// must know what the user is already following before any update can happen
return <span />;
}
const { follower, following } = this.props; // html
// Show follow preview for new users
if (!follower || !following)
return (
<span>
<label
className="button slim hollow secondary"
onClick={this.followLoggedOut}
>
{tt('g.follow')}
</label>
</span>
);
// Can't follow or ignore self
if (follower === following) return <span />;
const { followingWhat } = this.props; // redux
const { showFollow, showMute, fat, children } = this.props; // html
const { busy } = this.state;
const cnBusy = busy ? 'disabled' : '';
const cnActive = 'button' + (fat ? '' : ' slim');
const cnInactive = cnActive + ' hollow secondary ' + cnBusy;
return (
<span>
{showFollow &&
followingWhat !== 'blog' && (
<label className={cnInactive} onClick={this.follow}>
{tt('g.follow')}
</label>
)}
{showFollow &&
followingWhat === 'blog' && (
<label className={cnInactive} onClick={this.unfollow}>
{tt('g.unfollow')}
</label>
)}
{showMute &&
followingWhat !== 'ignore' && (
<label className={cnInactive} onClick={this.ignore}>
{tt('g.mute')}
</label>
)}
{showMute &&
followingWhat === 'ignore' && (
<label className={cnInactive} onClick={this.unignore}>
{tt('g.unmute')}
</label>
)}
{children && <span>&nbsp;&nbsp;{children}</span>}
</span>
);
}
}
const emptyMap = Map();
const emptySet = Set();
module.exports = connect(
(state, ownProps) => {
let { follower } = ownProps;
if (!follower) {
const current_user = state.user.get('current');
follower = current_user ? current_user.get('username') : null;
}
const { following } = ownProps;
const f = state.global.getIn(
['follow', 'getFollowingAsync', follower],
emptyMap
);
// the line below was commented out by val - I think it's broken so sometimes the loading indicator is shown forever
// const loading = f.get('blog_loading', false) || f.get('ignore_loading', false)
const loading = false;
const followingWhat = f.get('blog_result', emptySet).contains(following)
? 'blog'
: f.get('ignore_result', emptySet).contains(following)
? 'ignore'
: null;
return {
follower,
following,
followingWhat,
loading,
};
},
dispatch => ({
updateFollow: (follower, following, action, done) => {
const what = action ? [action] : [];
const json = ['follow', { follower, following, what }];
dispatch(
transactionActions.broadcastOperation({
type: 'custom_json',
operation: {
id: 'follow',
required_posting_auths: [follower],
json: JSON.stringify(json),
},
successCallback: done,
// TODO: Why?
errorCallback: done,
})
);
},
showLogin: e => {
if (e) e.preventDefault();
dispatch(userActions.showLogin());
},
})
)(Follow);
import React from 'react';
import { mount, configure, shallow } from 'enzyme';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import Follow from './index';
import rootReducer from 'app/redux/RootReducer';
import Adapter from 'enzyme-adapter-react-15';
const store = createStore(rootReducer);
configure({ adapter: new Adapter() });
describe('<Follow />', () => {
const wrapper = shallow(
<Provider store={store}>
<Follow />
</Provider>
);
const container = wrapper.instance();
it('renders without crashing', () => {
expect(wrapper).toBeTruthy();
expect(container).toBeTruthy();
expect(wrapper).toMatchSnapshot();
});
});
......@@ -78,16 +78,6 @@ class Header extends React.Component {
: null;
const user_title = name ? `${name} (@${user_name})` : user_name;
page_title = user_title;
if (route.params[1] === 'followers') {
page_title = tt('header_jsx.people_following', {
username: user_title,
});
}
if (route.params[1] === 'followed') {
page_title = tt('header_jsx.people_followed_by', {
username: user_title,
});
}
if (route.params[1] === 'curation-rewards') {
page_title = tt('header_jsx.curation_rewards_by', {
username: user_title,
......
......@@ -184,11 +184,6 @@ class LoginForm extends Component {
let postType = '';
if (opType === 'vote') {
postType = tt('loginform_jsx.login_to_vote');
} else if (
opType === 'custom_json' &&
loginBroadcastOperation.getIn(['operation', 'id']) === 'follow'
) {
postType = 'Login to Follow Users';
} else if (loginBroadcastOperation) {
// check for post or comment in operation
postType = loginBroadcastOperation.getIn(['operation', 'title'])
......
......@@ -16,7 +16,6 @@ import SignUp from 'app/components/modules/SignUp';
import Powerdown from 'app/components/modules/Powerdown';
import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
import TermsAgree from 'app/components/modules/TermsAgree';
import PostAdvancedSettings from 'app/components/modules/PostAdvancedSettings';
class Modals extends React.Component {
static defaultProps = {
......@@ -24,7 +23,6 @@ class Modals extends React.Component {
notifications: undefined,
removeNotification: () => {},
show_terms_modal: false,
show_promote_post_modal: false,
show_signup_modal: false,
show_bandwidth_error_modal: false,
show_powerdown_modal: false,
......@@ -40,7 +38,6 @@ class Modals extends React.Component {
show_powerdown_modal: PropTypes.bool,
show_bandwidth_error_modal: PropTypes.bool,
show_signup_modal: PropTypes.bool,
show_promote_post_modal: PropTypes.bool,
show_post_advanced_settings_modal: PropTypes.string,
hideLogin: PropTypes.func.isRequired,
username: PropTypes.string,
......@@ -49,7 +46,6 @@ class Modals extends React.Component {
hideTransfer: PropTypes.func.isRequired,
hidePowerdown: PropTypes.func.isRequired,
hideBandwidthError: PropTypes.func.isRequired,
hidePostAdvancedSettings: PropTypes.func.isRequired,
notifications: PropTypes.object,
show_terms_modal: PropTypes.bool,
removeNotification: PropTypes.func,
......@@ -77,10 +73,7 @@ class Modals extends React.Component {
show_terms_modal,
notifications,
removeNotification,
hidePromotePost,
show_promote_post_modal,
hideBandwidthError,
hidePostAdvancedSettings,
username,
} = this.props;
......@@ -168,17 +161,6 @@ class Modals extends React.Component {
</div>
</Reveal>
)}
{show_post_advanced_settings_modal && (
<Reveal
onHide={hidePostAdvancedSettings}
show={show_post_advanced_settings_modal ? true : false}
>
<CloseButton onClick={hidePostAdvancedSettings} />
<PostAdvancedSettings
formId={show_post_advanced_settings_modal}
/>
</Reveal>
)}
<NotificationStack
style={false}
notifications={notifications_array}
......@@ -197,7 +179,6 @@ export default connect(
show_confirm_modal: state.transaction.get('show_confirm_modal'),
show_transfer_modal: state.user.get('show_transfer_modal'),
show_powerdown_modal: state.user.get('show_powerdown_modal'),
show_promote_post_modal: state.user.get('show_promote_post_modal'),
show_signup_modal: state.user.get('show_signup_modal'),
notifications: state.app.get('notifications'),
show_terms_modal:
......@@ -232,10 +213,6 @@ export default connect(
if (e) e.preventDefault();
dispatch(userActions.hidePowerdown());
},
hidePromotePost: e => {
if (e) e.preventDefault();
dispatch(userActions.hidePromotePost());
},
hideSignUp: e => {
if (e) e.preventDefault();
dispatch(userActions.hideSignUp());
......@@ -246,10 +223,6 @@ export default connect(
transactionActions.dismissError({ key: 'bandwidthError' })
);
},
hidePostAdvancedSettings: e => {
if (e) e.preventDefault();
dispatch(userActions.hidePostAdvancedSettings());
},
// example: addNotification: ({key, message}) => dispatch({type: 'ADD_NOTIFICATION', payload: {key, message}}),
removeNotification: key =>
dispatch(appActions.removeNotification({ key })),
......
import React, { PropTypes, Component } from 'react';
import ReactDOM from 'react-dom';
import reactForm from 'app/utils/ReactForm';
import { SUBMIT_FORM_ID } from 'shared/constants';
import tt from 'counterpart';
import { fromJS } from 'immutable';
import * as userActions from 'app/redux/UserReducer';
class PostAdvancedSettings extends Component {
static propTypes = {
formId: React.PropTypes.string.isRequired,
};
constructor(props) {
super();
this.state = { payoutType: props.initialPayoutType };
this.initForm(props);
}
initForm(props) {
const { fields } = props;
reactForm({
fields,
instance: this,
name: 'advancedSettings',
initialValues: props.initialValues,
validation: values => {},
});
}
handlePayoutChange = event => {
this.setState({ payoutType: event.target.value });
};
render() {
const {
formId,
username,
defaultPayoutType,
initialPayoutType,
} = this.props;
const { payoutType } = this.state;
const { submitting, valid, handleSubmit } = this.state.advancedSettings;
const disabled =
submitting || !(valid || payoutType !== initialPayoutType);
const form = (
<form
onSubmit={handleSubmit(({ data }) => {
this.props.setPayoutType(formId, payoutType);
this.props.hideAdvancedSettings();
})}
>
<div className="row">
<div className="column">
<h4>
{tt(
'post_advanced_settings_jsx.payout_option_header'
)}
</h4>
<p>
{tt(
'post_advanced_settings_jsx.payout_option_description'
)}
</p>
</div>
</div>
<div className="row">
<div className="small-12 medium-6 large-12 columns">
<select
defaultValue={payoutType}
onChange={this.handlePayoutChange}
>
<option value="0%">
{tt('reply_editor.decline_payout')}
</option>
<option value="50%">
{tt('reply_editor.default_50_50')}
</option>
<option value="100%">
{tt('reply_editor.power_up_100')}
</option>
</select>
</div>
</div>
<br />
<div className="row">
<div className="column">
{tt('post_advanced_settings_jsx.current_default')}:{' '}
{defaultPayoutType === '0%'
? tt('reply_editor.decline_payout')
: defaultPayoutType === '50%'
? tt('reply_editor.default_50_50')
: tt('reply_editor.power_up_100')}
</div>
</div>
<div className="row">
<div className="column">
<a href={'/@' + usernam