diff --git a/app/soapbox/features/developers/developers_challenge.js b/app/soapbox/features/developers/developers_challenge.js
new file mode 100644
index 000000000..fe150e2ea
--- /dev/null
+++ b/app/soapbox/features/developers/developers_challenge.js
@@ -0,0 +1,84 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
+import Column from '../ui/components/column';
+import { SimpleForm, TextInput } from 'soapbox/features/forms';
+import { changeSetting } from 'soapbox/actions/settings';
+import snackbar from 'soapbox/actions/snackbar';
+
+const messages = defineMessages({
+ heading: { id: 'column.developers', defaultMessage: 'Developers' },
+ answerLabel: { id: 'developers.challenge.answer_label', defaultMessage: 'Answer' },
+ answerPlaceholder: { id: 'developers.challenge.answer_placeholder', defaultMessage: 'Your answer' },
+ success: { id: 'developers.challenge.success', defaultMessage: 'You are now a developer' },
+ fail: { id: 'developers.challenge.fail', defaultMessage: 'Wrong answer' },
+});
+
+export default @connect()
+@injectIntl
+class DevelopersChallenge extends React.Component {
+
+ static propTypes = {
+ intl: PropTypes.object.isRequired,
+ dispatch: PropTypes.func.isRequired,
+ }
+
+ state = {
+ answer: '',
+ }
+
+ handleChangeAnswer = e => {
+ this.setState({ answer: e.target.value });
+ }
+
+ handleSubmit = e => {
+ const { intl, dispatch } = this.props;
+ const { answer } = this.state;
+
+ if (answer === 'buzzfizz') {
+ dispatch(changeSetting(['isDeveloper'], true));
+ dispatch(snackbar.success(intl.formatMessage(messages.success)));
+ } else {
+ dispatch(snackbar.error(intl.formatMessage(messages.fail)));
+ }
+ }
+
+ render() {
+ const { intl } = this.props;
+
+ const challenge = `function fizzbuzz() {
+ return 'fizz|buzz'.split('|').reverse().join('');
+}`;
+
+ return (
+
+
+
+ fizzbuzz() }}
+ />
+
+ {challenge}
+
+
+
+
+
+
+
+
+ );
+ }
+
+}
diff --git a/app/soapbox/features/developers/developers_menu.js b/app/soapbox/features/developers/developers_menu.js
new file mode 100644
index 000000000..3caa036d8
--- /dev/null
+++ b/app/soapbox/features/developers/developers_menu.js
@@ -0,0 +1,90 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
+import { Link } from 'react-router-dom';
+import Column from '../ui/components/column';
+import Icon from 'soapbox/components/icon';
+import { changeSetting } from 'soapbox/actions/settings';
+import snackbar from 'soapbox/actions/snackbar';
+
+const messages = defineMessages({
+ heading: { id: 'column.developers', defaultMessage: 'Developers' },
+ leave: { id: 'developers.leave', defaultMessage: 'You have left developers' },
+});
+
+export default @connect()
+@injectIntl
+class DevelopersMenu extends React.Component {
+
+ static contextTypes = {
+ router: PropTypes.object,
+ };
+
+ static propTypes = {
+ intl: PropTypes.object.isRequired,
+ dispatch: PropTypes.func.isRequired,
+ }
+
+ leaveDevelopers = e => {
+ const { intl, dispatch } = this.props;
+
+ dispatch(changeSetting(['isDeveloper'], false));
+ dispatch(snackbar.success(intl.formatMessage(messages.leave)));
+
+ this.context.router.history.push('/');
+ e.preventDefault();
+ }
+
+ render() {
+ const { intl } = this.props;
+
+ return (
+
+
+
+ );
+ }
+
+}
diff --git a/app/soapbox/features/developers/index.js b/app/soapbox/features/developers/index.js
index 3c5734857..1302eab92 100644
--- a/app/soapbox/features/developers/index.js
+++ b/app/soapbox/features/developers/index.js
@@ -1,60 +1,28 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
-import { Link } from 'react-router-dom';
-import Column from '../ui/components/column';
-import Icon from 'soapbox/components/icon';
+import { connect } from 'react-redux';
+import { getSettings } from 'soapbox/actions/settings';
+import DevelopersMenu from './developers_menu';
+import DevelopersChallenge from './developers_challenge';
-const messages = defineMessages({
- heading: { id: 'column.developers', defaultMessage: 'Developers' },
-});
+const mapStateToProps = state => {
+ const settings = getSettings(state);
-export default @injectIntl
+ return {
+ isDeveloper: settings.get('isDeveloper'),
+ };
+};
+
+export default @connect(mapStateToProps)
class Developers extends React.Component {
static propTypes = {
- intl: PropTypes.object.isRequired,
+ isDeveloper: PropTypes.bool.isRequired,
}
render() {
- const { intl } = this.props;
-
- return (
-
-
-
- );
+ const { isDeveloper } = this.props;
+ return isDeveloper ? : ;
}
}
diff --git a/app/soapbox/features/preferences/index.js b/app/soapbox/features/preferences/index.js
index f904e62a2..39a394d2f 100644
--- a/app/soapbox/features/preferences/index.js
+++ b/app/soapbox/features/preferences/index.js
@@ -282,10 +282,6 @@ class Preferences extends ImmutablePureComponent {
hint={}
path={['demetricator']}
/>
- }
- path={['isDeveloper']}
- />
diff --git a/app/soapbox/features/ui/index.js b/app/soapbox/features/ui/index.js
index 2f69499a9..a8c2d4475 100644
--- a/app/soapbox/features/ui/index.js
+++ b/app/soapbox/features/ui/index.js
@@ -324,7 +324,7 @@ class SwitchingColumnsArea extends React.PureComponent {
-
+
diff --git a/app/styles/application.scss b/app/styles/application.scss
index 2918173a9..41ef7cf14 100644
--- a/app/styles/application.scss
+++ b/app/styles/application.scss
@@ -31,6 +31,7 @@
@import 'navigation';
@import 'placeholder';
@import 'autosuggest';
+@import 'developers';
// COMPONENTS
@import 'components/buttons';
diff --git a/app/styles/developers.scss b/app/styles/developers.scss
new file mode 100644
index 000000000..b33877120
--- /dev/null
+++ b/app/styles/developers.scss
@@ -0,0 +1,21 @@
+.developers-challenge {
+ .code {
+ font-family: 'Roboto Mono', monospace;
+ cursor: text;
+ background-color: var(--background-color);
+ }
+
+ span.code {
+ padding: 2px 4px;
+ border-radius: 4px;
+ }
+
+ pre.code {
+ line-height: 1.6em;
+ overflow-x: auto;
+ border-radius: 6px;
+ padding: 8px 12px;
+ margin: 20px 0;
+ word-break: break-all;
+ }
+}