diff --git a/client/modules/User/components/APIKeyForm.jsx b/client/modules/User/components/APIKeyForm.jsx
new file mode 100644
index 00000000..feb81135
--- /dev/null
+++ b/client/modules/User/components/APIKeyForm.jsx
@@ -0,0 +1,71 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+class APIKeyForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { keyLabel: '' };
+
+ this.addKey = this.addKey.bind(this);
+ }
+
+ addKey(event) {
+ // TODO
+ console.log('addKey');
+ this.props.updateSettings();
+ event.preventDefault();
+ return false;
+ }
+
+ removeKey(k) {
+ // TODO
+ console.log(k);
+ }
+
+ render() {
+ return (
+
+
Key label
+
+
+
+ {[{
+ id: 1,
+ label: 'MyFirstAPI',
+ createdAt: new Date(),
+ lastUsedAt: new Date()
+ }, {
+ id: 2,
+ label: 'MyOtherAPI',
+ createdAt: new Date(),
+ lastUsedAt: new Date()
+ }].map(v => (
+
+ {v.label} Created on: {v.createdAt.toLocaleDateString()} {v.createdAt.toLocaleTimeString()} |
+ Last used on: {v.lastUsedAt.toLocaleDateString()} {v.lastUsedAt.toLocaleTimeString()} |
+ |
+
))}
+
+
+
+ );
+ }
+}
+
+APIKeyForm.propTypes = {
+ updateSettings: PropTypes.func.isRequired,
+};
+
+export default APIKeyForm;
diff --git a/client/modules/User/pages/AccountView.jsx b/client/modules/User/pages/AccountView.jsx
index 2fb03b1f..d1bd6ba9 100644
--- a/client/modules/User/pages/AccountView.jsx
+++ b/client/modules/User/pages/AccountView.jsx
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import { reduxForm } from 'redux-form';
import { bindActionCreators } from 'redux';
-import { browserHistory } from 'react-router';
+import { Link, browserHistory } from 'react-router';
import InlineSVG from 'react-inlinesvg';
import axios from 'axios';
import { Helmet } from 'react-helmet';
@@ -22,8 +22,12 @@ class AccountView extends React.Component {
this.gotoHomePage = this.gotoHomePage.bind(this);
}
+ componentDidMount() {
+ document.body.className = this.props.theme;
+ }
+
closeAccountPage() {
- browserHistory.push(this.props.previousPath);
+ browserHistory.goBack();
}
gotoHomePage() {
@@ -47,6 +51,7 @@ class AccountView extends React.Component {
My Account
+
Advanced Settings
Or
@@ -59,7 +64,7 @@ function mapStateToProps(state) {
return {
initialValues: state.user, // <- initialValues for reduxForm
user: state.user,
- previousPath: state.ide.previousPath
+ theme: state.preferences.theme
};
}
@@ -86,7 +91,7 @@ function asyncValidate(formProps, dispatch, props) {
}
AccountView.propTypes = {
- previousPath: PropTypes.string.isRequired,
+ theme: PropTypes.string.isRequired
};
export default reduxForm({
diff --git a/client/modules/User/pages/AdvancedSettingsView.jsx b/client/modules/User/pages/AdvancedSettingsView.jsx
new file mode 100644
index 00000000..e963e5a4
--- /dev/null
+++ b/client/modules/User/pages/AdvancedSettingsView.jsx
@@ -0,0 +1,104 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { reduxForm } from 'redux-form';
+import { bindActionCreators } from 'redux';
+import { browserHistory } from 'react-router';
+import InlineSVG from 'react-inlinesvg';
+import axios from 'axios';
+import { Helmet } from 'react-helmet';
+import { updateSettings, initiateVerification } from '../actions';
+import { validateSettings } from '../../../utils/reduxFormUtils';
+import APIKeyForm from '../components/APIKeyForm';
+
+const exitUrl = require('../../../images/exit.svg');
+const logoUrl = require('../../../images/p5js-logo.svg');
+
+// TODO tmp
+const ident = () => {};
+
+class AccountView extends React.Component {
+ constructor(props) {
+ super(props);
+ this.closeAccountPage = this.closeAccountPage.bind(this);
+ this.gotoHomePage = this.gotoHomePage.bind(this);
+ }
+
+ componentDidMount() {
+ document.body.className = this.props.theme;
+ }
+
+ closeAccountPage() {
+ browserHistory.goBack();
+ }
+
+ gotoHomePage() {
+ browserHistory.push('/');
+ }
+
+ render() {
+ return (
+
+
+ p5.js Web Editor | Advanced Settings
+
+
+
+
+
+
+
+ );
+ }
+}
+
+function mapStateToProps(state) {
+ return {
+ initialValues: state.user, // <- initialValues for reduxForm
+ user: state.user,
+ previousPath: state.ide.previousPath,
+ theme: state.preferences.theme
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return bindActionCreators({ updateSettings, initiateVerification }, dispatch);
+}
+
+function asyncValidate(formProps, dispatch, props) {
+ const fieldToValidate = props.form._active;
+ if (fieldToValidate) {
+ const queryParams = {};
+ queryParams[fieldToValidate] = formProps[fieldToValidate];
+ queryParams.check_type = fieldToValidate;
+ return axios.get('/api/signup/duplicate_check', { params: queryParams })
+ .then((response) => {
+ if (response.data.exists) {
+ const error = {};
+ error[fieldToValidate] = response.data.message;
+ throw error;
+ }
+ });
+ }
+ return Promise.resolve(true).then(() => {});
+}
+
+AccountView.propTypes = {
+ theme: PropTypes.string.isRequired
+};
+
+export default reduxForm({
+ form: 'updateAllSettings',
+ fields: ['username', 'email', 'currentPassword', 'newPassword'],
+ validate: validateSettings,
+ asyncValidate,
+ asyncBlurFields: ['username', 'email', 'currentPassword']
+}, mapStateToProps, mapDispatchToProps)(AccountView);
diff --git a/client/routes.jsx b/client/routes.jsx
index baa89884..9389d226 100644
--- a/client/routes.jsx
+++ b/client/routes.jsx
@@ -9,6 +9,7 @@ import ResetPasswordView from './modules/User/pages/ResetPasswordView';
import EmailVerificationView from './modules/User/pages/EmailVerificationView';
import NewPasswordView from './modules/User/pages/NewPasswordView';
import AccountView from './modules/User/pages/AccountView';
+import AdvancedSettingsView from './modules/User/pages/AdvancedSettingsView';
// import SketchListView from './modules/Sketch/pages/SketchListView';
import { getUser } from './modules/User/actions';
import { stopSketch } from './modules/IDE/actions/ide';
@@ -38,6 +39,7 @@ const routes = store => (
+
diff --git a/client/styles/components/_form-container.scss b/client/styles/components/_form-container.scss
index 225dc155..4b371547 100644
--- a/client/styles/components/_form-container.scss
+++ b/client/styles/components/_form-container.scss
@@ -37,3 +37,17 @@
.form-container__exit-button {
@extend %none-themify-icon-with-hover;
}
+
+.form__table {
+ display: block;
+ max-width: 900px;
+ border-collapse: collapse;
+ & td {
+ max-width: 300px;
+ border: 1px solid #ddd;
+ padding: 0 10px 0 10px;
+ }
+ & tr:nth-child(even) {
+ background-color: #f2f2f2;
+ }
+}
diff --git a/client/styles/components/_forms.scss b/client/styles/components/_forms.scss
index 342a8c80..8fea3f3d 100644
--- a/client/styles/components/_forms.scss
+++ b/client/styles/components/_forms.scss
@@ -51,3 +51,20 @@
.form input[type="submit"]:disabled {
cursor: not-allowed;
}
+
+.form__button-remove {
+ @extend %forms-button;
+ margin: 1rem 0 1rem 0;
+ @include themify() {
+ color: getThemifyVariable('console-error-background-color');
+ border-color: getThemifyVariable('console-error-background-color');
+ &:enabled:hover {
+ border-color: getThemifyVariable('console-error-background-color');
+ background-color: getThemifyVariable('console-error-background-color');
+ }
+ &:enabled:active {
+ border-color: getThemifyVariable('console-error-background-color');
+ background-color: getThemifyVariable('console-error-background-color');
+ }
+ }
+}
diff --git a/server/routes/server.routes.js b/server/routes/server.routes.js
index adade10d..2f39e924 100644
--- a/server/routes/server.routes.js
+++ b/server/routes/server.routes.js
@@ -87,6 +87,14 @@ router.get('/account', (req, res) => {
}
});
+router.get('/account/advanced', (req, res) => {
+ if (req.user) {
+ res.send(renderIndex());
+ } else {
+ res.redirect('/login');
+ }
+});
+
router.get('/about', (req, res) => {
res.send(renderIndex());
});