diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js
index 28255aeb5..360ceaa93 100644
--- a/client/coral-admin/src/AppRouter.js
+++ b/client/coral-admin/src/AppRouter.js
@@ -10,6 +10,7 @@ import Configure from 'routes/Configure';
import StreamSettings from './routes/Configure/containers/StreamSettings';
import ModerationSettings from './routes/Configure/containers/ModerationSettings';
import TechSettings from './routes/Configure/containers/TechSettings';
+import OrganizationSettings from './routes/Configure/containers/OrganizationSettings';
import { ModerationLayout, Moderation } from 'routes/Moderation';
@@ -25,6 +26,7 @@ const routes = (
+
diff --git a/client/coral-admin/src/reducers/install.js b/client/coral-admin/src/reducers/install.js
index c0a694977..8d96b9b93 100644
--- a/client/coral-admin/src/reducers/install.js
+++ b/client/coral-admin/src/reducers/install.js
@@ -5,6 +5,7 @@ const initialState = {
isLoading: false,
data: {
settings: {
+ organizationContactEmail: '',
organizationName: '',
domains: {
whitelist: [],
@@ -19,6 +20,7 @@ const initialState = {
},
errors: {
organizationName: '',
+ organizationContactEmail: '',
username: '',
email: '',
password: '',
diff --git a/client/coral-admin/src/routes/Configure/components/Configure.js b/client/coral-admin/src/routes/Configure/components/Configure.js
index 4d88f8420..bcd48c21c 100644
--- a/client/coral-admin/src/routes/Configure/components/Configure.js
+++ b/client/coral-admin/src/routes/Configure/components/Configure.js
@@ -8,7 +8,14 @@ import SaveChangesDialog from './SaveChangesDialog';
class Configure extends React.Component {
render() {
- const { canSave, currentUser, root, savePending, settings } = this.props;
+ const {
+ canSave,
+ currentUser,
+ root,
+ savePending,
+ settings,
+ clearPending,
+ } = this.props;
if (!can(currentUser, 'UPDATE_CONFIG')) {
return
{t('configure.access_message')}
;
@@ -17,6 +24,9 @@ class Configure extends React.Component {
const passProps = {
root,
settings,
+ savePending,
+ clearPending,
+ canSave,
};
return (
@@ -41,6 +51,9 @@ class Configure extends React.Component {
-
{t('configure.tech_settings')}
+ -
+ {t('configure.organization_information')}
+
{canSave ? (
@@ -81,6 +94,7 @@ Configure.propTypes = {
children: PropTypes.node.isRequired,
saveDialog: PropTypes.bool,
hideSaveDialog: PropTypes.func.isRequired,
+ clearPending: PropTypes.func.isRequired,
};
export default Configure;
diff --git a/client/coral-admin/src/routes/Configure/components/OrganizationSettings.css b/client/coral-admin/src/routes/Configure/components/OrganizationSettings.css
new file mode 100644
index 000000000..2468496b7
--- /dev/null
+++ b/client/coral-admin/src/routes/Configure/components/OrganizationSettings.css
@@ -0,0 +1,87 @@
+.label {
+ display: block;
+}
+
+.detailList {
+ padding: 0;
+ margin: 0;
+}
+
+.detailLabel {
+ color: #000;
+ font-size: 1.1em;
+ font-weight: bold;
+ display: block;
+ margin-bottom: 4px;
+}
+
+.detailValue {
+ padding: 6px 0;
+ border: solid 1px transparent;
+ display: block;
+ font-size: 1.1em;
+ border-radius: 2px;
+ color: #424242;
+ box-sizing: border-box;
+ min-width: 300px;
+}
+
+.editable {
+ padding-left: 10px;
+ padding-right: 10px;
+ border-color: grey;
+}
+
+.detailItem {
+ margin-bottom: 16px;
+ list-style: none;
+}
+
+.button, .button:disabled {
+ background: white;
+ border: solid 1px grey;
+}
+
+.actionBox {
+ flex-grow: 0;
+}
+
+.cancelButton {
+ padding: 10px;
+ display: block;
+ color: #4f5c67;
+ font-weight: 500;
+
+ &:hover {
+ cursor: pointer;
+ }
+}
+
+.changedSave {
+ background-color: #00796B;
+ color: white;
+}
+
+.errorList {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.errorItem {
+ padding: 5px 10px;
+ margin-bottom: 20px;
+ color: #b71c1c;
+ border-radius: 2px;
+ display: inline-block;
+ background: #F9D3CE;
+}
+
+.container {
+ display: flex;
+}
+
+.content {
+ flex-grow: 1;
+ padding-right: 40px;
+}
\ No newline at end of file
diff --git a/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js b/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js
new file mode 100644
index 000000000..38f211781
--- /dev/null
+++ b/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js
@@ -0,0 +1,187 @@
+import React from 'react';
+import cn from 'classnames';
+import { Button } from 'coral-ui';
+import PropTypes from 'prop-types';
+import styles from './OrganizationSettings.css';
+import Slot from 'coral-framework/components/Slot';
+import t from 'coral-framework/services/i18n';
+import ConfigurePage from './ConfigurePage';
+import ConfigureCard from 'coral-framework/components/ConfigureCard';
+import validate from 'coral-framework/helpers/validate';
+import errorMsj from 'coral-framework/helpers/error';
+
+class OrganizationSettings extends React.Component {
+ state = { editing: false, errors: [] };
+
+ addError = err => {
+ if (this.state.errors.indexOf(err) === -1) {
+ this.setState(({ errors }) => ({
+ errors: errors.concat(err),
+ }));
+ }
+ };
+
+ removeError = err => {
+ this.setState(({ errors }) => ({
+ errors: errors.filter(i => i !== err),
+ }));
+ };
+
+ toggleEditing = () => {
+ this.setState(({ editing }) => ({
+ editing: !editing,
+ }));
+ };
+
+ disableEditing = () => {
+ this.setState(() => ({
+ editing: false,
+ }));
+ };
+
+ updateName = event => {
+ const updater = { organizationName: { $set: event.target.value } };
+ this.props.updatePending({ updater });
+ };
+
+ updateEmail = event => {
+ let error = null;
+ const email = event.target.value;
+
+ // Add a blocker error
+ if (!validate.email(email)) {
+ error = true;
+ this.addError('email');
+ } else {
+ this.removeError('email');
+ }
+
+ const updater = { organizationContactEmail: { $set: email } };
+ const errorUpdater = { organizationEmail: { $set: error } };
+
+ this.props.updatePending({ updater, errorUpdater });
+ };
+
+ cancelEditing = () => {
+ this.disableEditing();
+ this.props.clearPending();
+ };
+
+ save = async () => {
+ await this.props.savePending();
+ this.disableEditing();
+ };
+
+ displayErrors = (errors = []) => (
+
+ {errors.map((errKey, i) => (
+ -
+ {errorMsj[errKey]}
+
+ ))}
+
+ );
+
+ render() {
+ const { settings, slotPassthrough, canSave } = this.props;
+ const hasErrors = this.state.errors.length;
+
+ return (
+
+ {t('configure.organization_info_copy')}
+ {t('configure.organization_info_copy_2')}
+
+
+
+ {this.displayErrors(this.state.errors)}
+
+
+ {!this.state.editing ? (
+
+
+
+ ) : (
+
+ {canSave && !hasErrors ? (
+
+ ) : (
+
+ )}
+
+ {t('cancel')}
+
+
+ )}
+
+
+
+
+ );
+ }
+}
+
+OrganizationSettings.propTypes = {
+ savePending: PropTypes.func.isRequired,
+ clearPending: PropTypes.func.isRequired,
+ updatePending: PropTypes.func.isRequired,
+ errors: PropTypes.object.isRequired,
+ settings: PropTypes.object.isRequired,
+ slotPassthrough: PropTypes.object.isRequired,
+ canSave: PropTypes.bool.isRequired,
+};
+
+export default OrganizationSettings;
diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js
index 9f980d31b..7f0951154 100644
--- a/client/coral-admin/src/routes/Configure/containers/Configure.js
+++ b/client/coral-admin/src/routes/Configure/containers/Configure.js
@@ -16,6 +16,7 @@ import {
hideSaveDialog,
} from '../../../actions/configure';
import Configure from '../components/Configure';
+import OrganizationSettings from './OrganizationSettings';
import { withRouter } from 'react-router';
class ConfigureContainer extends React.Component {
@@ -83,18 +84,21 @@ class ConfigureContainer extends React.Component {
return
;
}
+ const activeSection = this.props.routes[3].path;
+
return (
{this.props.children}
@@ -110,10 +114,12 @@ const withConfigureQuery = withQuery(
...${getDefinitionName(StreamSettings.fragments.settings)}
...${getDefinitionName(TechSettings.fragments.settings)}
...${getDefinitionName(ModerationSettings.fragments.settings)}
+ ...${getDefinitionName(OrganizationSettings.fragments.settings)}
}
...${getDefinitionName(StreamSettings.fragments.root)}
...${getDefinitionName(TechSettings.fragments.root)}
...${getDefinitionName(ModerationSettings.fragments.root)}
+ ...${getDefinitionName(OrganizationSettings.fragments.root)}
}
${StreamSettings.fragments.root}
${StreamSettings.fragments.settings}
@@ -121,6 +127,8 @@ const withConfigureQuery = withQuery(
${TechSettings.fragments.settings}
${ModerationSettings.fragments.root}
${ModerationSettings.fragments.settings}
+ ${OrganizationSettings.fragments.root}
+ ${OrganizationSettings.fragments.settings}
`,
{
options: () => ({
diff --git a/client/coral-admin/src/routes/Configure/containers/OrganizationSettings.js b/client/coral-admin/src/routes/Configure/containers/OrganizationSettings.js
new file mode 100644
index 000000000..79ab70f69
--- /dev/null
+++ b/client/coral-admin/src/routes/Configure/containers/OrganizationSettings.js
@@ -0,0 +1,53 @@
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import { compose, gql } from 'react-apollo';
+import OrganizationSettings from '../components/OrganizationSettings';
+import withFragments from 'coral-framework/hocs/withFragments';
+import { getSlotFragmentSpreads } from 'coral-framework/utils';
+import { updatePending } from '../../../actions/configure';
+import { mapProps } from 'recompose';
+
+const slots = ['adminOrganizationSettings'];
+
+const mapStateToProps = state => ({
+ errors: state.configure.errors,
+});
+
+const mapDispatchToProps = dispatch =>
+ bindActionCreators(
+ {
+ updatePending,
+ },
+ dispatch
+ );
+
+export default compose(
+ withFragments({
+ root: gql`
+ fragment TalkAdmin_OrganizationSettings_root on RootQuery {
+ __typename
+ ${getSlotFragmentSpreads(slots, 'root')}
+ }
+ `,
+ settings: gql`
+ fragment TalkAdmin_OrganizationSettings_settings on Settings {
+ organizationName
+ organizationContactEmail
+ ${getSlotFragmentSpreads(slots, 'settings')}
+ }
+ `,
+ }),
+ connect(mapStateToProps, mapDispatchToProps),
+ mapProps(({ root, settings, updatePending, errors, ...rest }) => ({
+ slotPassthrough: {
+ root,
+ settings,
+ updatePending,
+ errors,
+ },
+ updatePending,
+ settings,
+ errors,
+ ...rest,
+ }))
+)(OrganizationSettings);
diff --git a/client/coral-admin/src/routes/Install/components/Install.js b/client/coral-admin/src/routes/Install/components/Install.js
index 14afc12f5..4e0024102 100644
--- a/client/coral-admin/src/routes/Install/components/Install.js
+++ b/client/coral-admin/src/routes/Install/components/Install.js
@@ -1,15 +1,16 @@
-import React, { Component } from 'react';
+import React from 'react';
import styles from './Install.css';
import { Wizard, WizardNav } from 'coral-ui';
import Layout from 'coral-admin/src/components/Layout';
+import PropTypes from 'prop-types';
import InitialStep from './Steps/InitialStep';
-import AddOrganizationName from './Steps/AddOrganizationName';
+import OrganizationDetails from './Steps/OrganizationDetails';
import CreateYourAccount from './Steps/CreateYourAccount';
import PermittedDomainsStep from './Steps/PermittedDomainsStep';
import FinalStep from './Steps/FinalStep';
-export default class Install extends Component {
+class Install extends React.Component {
handleDomainsChange = value => {
this.props.updatePermittedDomains(value);
};
@@ -55,7 +56,7 @@ export default class Install extends Component {
goToStep={this.props.goToStep}
>
- {
showErrors={install.showErrors}
errorMsg={install.errors.organizationName}
/>
+
+
+