From d5b134c653a962dcda76ef89af2065d801139dad Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Wed, 15 Feb 2017 19:17:46 -0800 Subject: [PATCH 1/6] Update version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 048f33c404a..9b146fd4874 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "reaction", "description": "Reaction is a modern reactive, real-time event driven ecommerce platform.", - "version": "0.19.0", + "version": "0.20.0", "main": "main.js", "directories": { "test": "tests" From 8dd49b43c45a6ab6f7d3712b7344bdf64df25c25 Mon Sep 17 00:00:00 2001 From: lorenzo Date: Sat, 18 Feb 2017 20:11:53 +0000 Subject: [PATCH 2/6] new meta key in registry, allow package registry items to override default meta title --- client/modules/router/main.js | 5 +++-- lib/api/router/metadata.js | 10 +++++++--- lib/collections/schemas/registry.js | 6 ++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/client/modules/router/main.js b/client/modules/router/main.js index 8ea4eaff9d4..e011180a959 100644 --- a/client/modules/router/main.js +++ b/client/modules/router/main.js @@ -192,14 +192,13 @@ Router.initPackageRoutes = () => { // registryItems if (registryItem.route) { const { + meta, route, template, layout, workflow } = registryItem; - // console.log(registryItem); - // get registry route name const name = getRegistryRouteName(pkg.name, registryItem); @@ -208,6 +207,7 @@ Router.initPackageRoutes = () => { const newRouteConfig = { route, options: { + meta, name, template, layout, @@ -218,6 +218,7 @@ Router.initPackageRoutes = () => { } } }; + // push new routes newRoutes.push(newRouteConfig); } // end registryItems diff --git a/lib/api/router/metadata.js b/lib/api/router/metadata.js index 30f26b876fb..b5ec80e1421 100644 --- a/lib/api/router/metadata.js +++ b/lib/api/router/metadata.js @@ -56,12 +56,16 @@ export const MetaData = { title = titleCase(params.slug); // fallback to route name } else if (context.route && context.route.name) { - const routeName = context.route.name; + const route = context.route; + const routeName = route.name; // default index to Shop Name if (routeName === "index") { title = titleCase(shop.name); - // default routes to route's name - } else { + // check for meta in package route + } else if (route.options.meta && route.options.meta.title) { + title = titleCase(route.options.meta.title); + } // default routes to route's name + else { title = titleCase(routeName); } } diff --git a/lib/collections/schemas/registry.js b/lib/collections/schemas/registry.js index 39c5e7dce3d..ec491d0d997 100644 --- a/lib/collections/schemas/registry.js +++ b/lib/collections/schemas/registry.js @@ -93,6 +93,12 @@ export const Registry = new SimpleSchema({ type: [String], optional: true, label: "Audience" + }, + meta: { + label: "Meta", + type: Object, + optional: true, + blackbox: true } }); From acf4157d9923b736da449909b8b0a81a20bfb9f8 Mon Sep 17 00:00:00 2001 From: Erik Kieckhafer Date: Thu, 23 Feb 2017 13:08:21 -0800 Subject: [PATCH 3/6] lint fixes --- lib/api/router/metadata.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/api/router/metadata.js b/lib/api/router/metadata.js index b5ec80e1421..633202febb1 100644 --- a/lib/api/router/metadata.js +++ b/lib/api/router/metadata.js @@ -64,8 +64,8 @@ export const MetaData = { // check for meta in package route } else if (route.options.meta && route.options.meta.title) { title = titleCase(route.options.meta.title); - } // default routes to route's name - else { + } else { + // default routes to route's name title = titleCase(routeName); } } From 5eed2486a121188e7f7cd05bceb07510a2cb2dad Mon Sep 17 00:00:00 2001 From: Joy Warugu Date: Fri, 24 Feb 2017 00:17:10 +0300 Subject: [PATCH 4/6] Rewrite example payment settings pane to react #1817 (#1848) * Have base to be release20 * Nitpick change on index --- .../included/payments-example/client/index.js | 2 +- .../components/exampleSettingsForm.js | 41 ++++++++++ .../client/settings/components/index.js | 1 + .../exampleSettingsFormContainer.js | 80 +++++++++++++++++++ .../client/settings/containers/index.js | 1 + .../client/settings/example.html | 58 -------------- .../client/settings/example.js | 46 ----------- .../client/settings/templates/example.html | 5 ++ .../client/settings/templates/example.js | 11 +++ 9 files changed, 140 insertions(+), 105 deletions(-) create mode 100644 imports/plugins/included/payments-example/client/settings/components/exampleSettingsForm.js create mode 100644 imports/plugins/included/payments-example/client/settings/components/index.js create mode 100644 imports/plugins/included/payments-example/client/settings/containers/exampleSettingsFormContainer.js create mode 100644 imports/plugins/included/payments-example/client/settings/containers/index.js delete mode 100644 imports/plugins/included/payments-example/client/settings/example.html delete mode 100644 imports/plugins/included/payments-example/client/settings/example.js create mode 100644 imports/plugins/included/payments-example/client/settings/templates/example.html create mode 100644 imports/plugins/included/payments-example/client/settings/templates/example.js diff --git a/imports/plugins/included/payments-example/client/index.js b/imports/plugins/included/payments-example/client/index.js index 0b32b322c05..a2e0dea67b9 100644 --- a/imports/plugins/included/payments-example/client/index.js +++ b/imports/plugins/included/payments-example/client/index.js @@ -1,2 +1,2 @@ import "./checkout/example"; -import "./settings/example"; +import "./settings/templates/example"; diff --git a/imports/plugins/included/payments-example/client/settings/components/exampleSettingsForm.js b/imports/plugins/included/payments-example/client/settings/components/exampleSettingsForm.js new file mode 100644 index 00000000000..b75015f3441 --- /dev/null +++ b/imports/plugins/included/payments-example/client/settings/components/exampleSettingsForm.js @@ -0,0 +1,41 @@ +import React, { Component, PropTypes } from "react"; +import { FieldGroup, Translation } from "/imports/plugins/core/ui/client/components"; + +class ExampleSettingsForm extends Component { + render() { + const { packageData } = this.props; + + return ( +
+ { !packageData.settings.apiKey && +
+ +
+ } + +
+ + + + + +
+ ); + } +} + +ExampleSettingsForm.propTypes = { + onChange: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + packageData: PropTypes.object +}; + +export default ExampleSettingsForm; + diff --git a/imports/plugins/included/payments-example/client/settings/components/index.js b/imports/plugins/included/payments-example/client/settings/components/index.js new file mode 100644 index 00000000000..b49222b0c7f --- /dev/null +++ b/imports/plugins/included/payments-example/client/settings/components/index.js @@ -0,0 +1 @@ +export { default as ExampleSettingsForm } from "./exampleSettingsForm.js"; diff --git a/imports/plugins/included/payments-example/client/settings/containers/exampleSettingsFormContainer.js b/imports/plugins/included/payments-example/client/settings/containers/exampleSettingsFormContainer.js new file mode 100644 index 00000000000..5da59806e94 --- /dev/null +++ b/imports/plugins/included/payments-example/client/settings/containers/exampleSettingsFormContainer.js @@ -0,0 +1,80 @@ +import React, { Component, PropTypes } from "react"; +import { Meteor } from "meteor/meteor"; +import { composeWithTracker } from "/lib/api/compose"; +import { Packages } from "/lib/collections"; +import { Loading } from "/imports/plugins/core/ui/client/components"; +import { TranslationProvider } from "/imports/plugins/core/ui/client/providers"; +import { Reaction, i18next } from "/client/api"; +import { ExampleSettingsForm } from "../components"; + +class ExampleSettingsFormContainer extends Component { + constructor(props) { + super(props); + + this.state = { + apiKey: "" + }; + + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + this.saveUpdate = this.saveUpdate.bind(this); + } + + handleChange(e) { + e.preventDefault(); + this.setState({ apiKey: e.target.value }); + } + + handleSubmit(e) { + e.preventDefault(); + + const packageId = this.props.packageData._id; + const settingsKey = this.props.packageData.registry[0].settingsKey; + const apiKey = this.state.apiKey; + + const fields = [{ + property: "apiKey", + value: apiKey + }]; + + this.saveUpdate(fields, packageId, settingsKey); + } + + saveUpdate(fields, id, settingsKey) { + Meteor.call("registry/update", id, settingsKey, fields, (err) => { + if (err) { + return Alerts.toast(i18next.t("admin.settings.saveFailed"), "error"); + } + return Alerts.toast(i18next.t("admin.settings.saveSuccess"), "success"); + }); + } + + render() { + return ( + + + + ); + } +} + +ExampleSettingsFormContainer.propTypes = { + packageData: PropTypes.object +}; + +const composer = ({}, onData) => { + const subscription = Meteor.subscribe("Packages"); + if (subscription.ready()) { + const packageData = Packages.findOne({ + name: "example-paymentmethod", + shopId: Reaction.getShopId() + }); + onData(null, { packageData }); + } +}; + +export default composeWithTracker(composer, Loading)(ExampleSettingsFormContainer); diff --git a/imports/plugins/included/payments-example/client/settings/containers/index.js b/imports/plugins/included/payments-example/client/settings/containers/index.js new file mode 100644 index 00000000000..a04ab5d1421 --- /dev/null +++ b/imports/plugins/included/payments-example/client/settings/containers/index.js @@ -0,0 +1 @@ +export { default as ExampleSettingsFormContainer } from "./exampleSettingsFormContainer"; diff --git a/imports/plugins/included/payments-example/client/settings/example.html b/imports/plugins/included/payments-example/client/settings/example.html deleted file mode 100644 index 7b123e41d47..00000000000 --- a/imports/plugins/included/payments-example/client/settings/example.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - diff --git a/imports/plugins/included/payments-example/client/settings/example.js b/imports/plugins/included/payments-example/client/settings/example.js deleted file mode 100644 index ce9cdd7ba4f..00000000000 --- a/imports/plugins/included/payments-example/client/settings/example.js +++ /dev/null @@ -1,46 +0,0 @@ -import { Template } from "meteor/templating"; -import { Reaction, i18next } from "/client/api"; -import { Packages } from "/lib/collections"; -import { ExamplePackageConfig } from "../../lib/collections/schemas"; - -import "./example.html"; - - -Template.exampleSettings.helpers({ - ExamplePackageConfig() { - return ExamplePackageConfig; - }, - packageData() { - return Packages.findOne({ - name: "example-paymentmethod", - shopId: Reaction.getShopId() - }); - } -}); - - -Template.example.helpers({ - packageData: function () { - return Packages.findOne({ - name: "example-paymentmethod", - shopId: Reaction.getShopId() - }); - } -}); - -Template.example.events({ - "click [data-event-action=showExampleSettings]": function () { - Reaction.showActionView(); - } -}); - -AutoForm.hooks({ - "example-update-form": { - onSuccess: function () { - return Alerts.toast(i18next.t("admin.settings.saveSuccess"), "success"); - }, - onError: function () { - return Alerts.toast(`${i18next.t("admin.settings.saveFailed")} ${error}`, "error"); - } - } -}); diff --git a/imports/plugins/included/payments-example/client/settings/templates/example.html b/imports/plugins/included/payments-example/client/settings/templates/example.html new file mode 100644 index 00000000000..f70d1753254 --- /dev/null +++ b/imports/plugins/included/payments-example/client/settings/templates/example.html @@ -0,0 +1,5 @@ + diff --git a/imports/plugins/included/payments-example/client/settings/templates/example.js b/imports/plugins/included/payments-example/client/settings/templates/example.js new file mode 100644 index 00000000000..f0793d9c9f1 --- /dev/null +++ b/imports/plugins/included/payments-example/client/settings/templates/example.js @@ -0,0 +1,11 @@ +import { ExampleSettingsFormContainer } from "../containers"; +import { Template } from "meteor/templating"; +import "./example.html"; + +Template.exampleSettings.helpers({ + ExampleSettings() { + return { + component: ExampleSettingsFormContainer + }; + } +}); From b84b6cb9a10a0db5cb9f9fb09772cf78473e8d82 Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Mon, 27 Feb 2017 01:54:46 -0800 Subject: [PATCH 5/6] Convert social settings to React with new cards (#1854) * Convert social settings to React with new cards * Save card open state * Add new SettingsCard component - SettingsCard component wraps many components necessary for a dashboard settings card. - Added method for updating user preferences * Added a custom React semi-auto Form component To help standardize all settings cards a new `Form` component has been added that can use `SimpleSchema` to generate a basic, single level form with validation. * Update social settings and form component - Add success message on submit - Remove unused code - Fix glitch with auto form and error messages * Added prop type for switchName --- client/modules/core/main.js | 8 + .../core/ui/client/components/cards/card.js | 9 +- .../ui/client/components/cards/cardHeader.js | 38 ++- .../core/ui/client/components/cards/index.js | 1 + .../client/components/cards/settingsCard.js | 67 +++++ .../core/ui/client/components/forms/form.js | 255 ++++++++++++++++++ .../ui/client/components/forms/formActions.js | 22 ++ .../core/ui/client/components/forms/index.js | 2 + .../core/ui/client/components/index.js | 3 +- .../default-theme/client/styles/cards.less | 4 + .../social/client/components/index.js | 1 + .../social/client/components/settings.js | 110 ++++++++ .../client/containers/socialContainer.js | 3 +- .../containers/socialSettingsContainer.js | 86 ++++++ .../client/templates/dashboard/social.html | 72 +---- .../client/templates/dashboard/social.js | 28 +- .../included/social/server/i18n/en.json | 11 +- .../plugins/included/social/server/index.js | 1 + .../plugins/included/social/server/methods.js | 44 +++ lib/collections/schemas/social.js | 2 + 20 files changed, 661 insertions(+), 106 deletions(-) create mode 100644 imports/plugins/core/ui/client/components/cards/settingsCard.js create mode 100644 imports/plugins/core/ui/client/components/forms/form.js create mode 100644 imports/plugins/core/ui/client/components/forms/formActions.js create mode 100644 imports/plugins/core/ui/client/components/forms/index.js create mode 100644 imports/plugins/included/social/client/components/settings.js create mode 100644 imports/plugins/included/social/client/containers/socialSettingsContainer.js create mode 100644 imports/plugins/included/social/server/methods.js diff --git a/client/modules/core/main.js b/client/modules/core/main.js index 3c9c4c8eafd..31f384e7370 100644 --- a/client/modules/core/main.js +++ b/client/modules/core/main.js @@ -215,6 +215,14 @@ export default { return false; }, + updateUserPreferences(packageName, preference, values) { + const currentPreference = this.getUserPreferences(packageName, preference, {}); + return this.setUserPreferences(packageName, preference, { + ...currentPreference, + ...values + }); + }, + getShopId() { return this.shopId; }, diff --git a/imports/plugins/core/ui/client/components/cards/card.js b/imports/plugins/core/ui/client/components/cards/card.js index 77029ef13a3..d39fef1f35c 100644 --- a/imports/plugins/core/ui/client/components/cards/card.js +++ b/imports/plugins/core/ui/client/components/cards/card.js @@ -20,11 +20,11 @@ class Card extends Component { handleExpanderClick = (event) => { this.setState({ expanded: !this.state.expanded + }, () => { + if (typeof this.props.onExpand === "function") { + this.props.onExpand(event, this, this.props.name, this.state.expanded); + } }); - - if (typeof this.props.onExpand === "function") { - this.props.onExpand(event, this); - } } render() { @@ -67,6 +67,7 @@ Card.propTypes = { children: PropTypes.node, expandable: PropTypes.bool, expanded: PropTypes.bool, + name: PropTypes.string, onExpand: PropTypes.func, style: PropTypes.object }; diff --git a/imports/plugins/core/ui/client/components/cards/cardHeader.js b/imports/plugins/core/ui/client/components/cards/cardHeader.js index 9323972c798..adc89fd1a81 100644 --- a/imports/plugins/core/ui/client/components/cards/cardHeader.js +++ b/imports/plugins/core/ui/client/components/cards/cardHeader.js @@ -2,6 +2,7 @@ import React, { Component, PropTypes } from "react"; import classnames from "classnames"; import CardTitle from "./cardTitle"; import IconButton from "../button/iconButton"; +import Icon from "../icon/icon"; import Switch from "../switch/switch"; class CardHeader extends Component { @@ -16,10 +17,13 @@ class CardHeader extends Component { expandOnSwitchOn: PropTypes.bool, expanded: PropTypes.bool, i18nKeyTitle: PropTypes.string, + icon: PropTypes.string, + imageView: PropTypes.node, onClick: PropTypes.func, onSwitchChange: PropTypes.func, showSwitch: PropTypes.bool, - switchChecked: PropTypes.bool, + switchName: PropTypes.string, + switchOn: PropTypes.bool, title: PropTypes.string }; @@ -53,6 +57,26 @@ class CardHeader extends Component { return null; } + renderImage() { + if (this.props.icon) { + return ( +
+ +
+ ); + } + + if (this.props.imageView) { + return ( +
+ {this.props.imageView} +
+ ); + } + + return null; + } + renderDisclsoureArrow() { const expanderClassName = classnames({ rui: true, @@ -76,7 +100,8 @@ class CardHeader extends Component { if (this.props.showSwitch) { return ( ); @@ -97,6 +122,7 @@ class CardHeader extends Component { return (
+ {this.renderImage()} {this.renderTitle()}
@@ -109,8 +135,12 @@ class CardHeader extends Component { return (
- {this.renderTitle()} - {this.props.children} +
+ {this.renderTitle()} +
+
+ {this.props.children} +
); } diff --git a/imports/plugins/core/ui/client/components/cards/index.js b/imports/plugins/core/ui/client/components/cards/index.js index 2f7708ed970..4e0220909be 100644 --- a/imports/plugins/core/ui/client/components/cards/index.js +++ b/imports/plugins/core/ui/client/components/cards/index.js @@ -3,3 +3,4 @@ export { default as CardHeader } from "./cardHeader"; export { default as CardTitle } from "./cardTitle"; export { default as CardBody } from "./cardBody"; export { default as CardGroup } from "./cardGroup"; +export { default as SettingsCard } from "./settingsCard"; diff --git a/imports/plugins/core/ui/client/components/cards/settingsCard.js b/imports/plugins/core/ui/client/components/cards/settingsCard.js new file mode 100644 index 00000000000..2e41371f5f6 --- /dev/null +++ b/imports/plugins/core/ui/client/components/cards/settingsCard.js @@ -0,0 +1,67 @@ +/** + * Settings Card is a composite component to standardize the + * creation settings cards (panels) in the dashboard. + */ + +import React, { Component, PropTypes } from "react"; +import Blaze from "meteor/gadicc:blaze-react-component"; +import { Card, CardHeader, CardBody } from "/imports/plugins/core/ui/client/components"; + +class SettingsCard extends Component { + static propTypes = { + children: PropTypes.node, + enabled: PropTypes.bool, + expanded: PropTypes.bool, + i18nKeyTitle: PropTypes.string, + icon: PropTypes.string, + name: PropTypes.string, + onExpand: PropTypes.func, + onSwitchChange: PropTypes.func, + template: PropTypes.any, + title: PropTypes.string + } + + handleSwitchChange = (event, isChecked) => { + if (typeof this.props.onSwitchChange === "function") { + this.props.onSwitchChange(event, isChecked, this.props.name, this); + } + } + + renderCardBody() { + if (this.props.template) { + return ( + + ); + } + + return this.props.children; + } + + render() { + return ( + + + + {this.renderCardBody()} + + + ); + } +} + +export default SettingsCard; diff --git a/imports/plugins/core/ui/client/components/forms/form.js b/imports/plugins/core/ui/client/components/forms/form.js new file mode 100644 index 00000000000..9e2b4ab00dd --- /dev/null +++ b/imports/plugins/core/ui/client/components/forms/form.js @@ -0,0 +1,255 @@ +import React, { Component, PropTypes } from "react"; +import { map, update, set, at, isEqual } from "lodash"; +import classnames from "classnames"; +import { toCamelCase } from "/lib/api"; +import { Switch, Button, TextField, FormActions } from "../"; + +class Form extends Component { + static propTypes = { + doc: PropTypes.object, + docPath: PropTypes.string, + hideFields: PropTypes.arrayOf(PropTypes.string), + name: PropTypes.string, + onSubmit: PropTypes.func, + schema: PropTypes.object + } + + constructor(props) { + super(props); + + this.state = { + doc: props.doc, + schema: this.validationSchema(), + isValid: undefined + }; + } + + componentWillReceiveProps(nextProps) { + if (isEqual(nextProps.doc, this.props.doc) === false) { + this.setState({ + doc: nextProps.doc, + schema: this.validationSchema() + }); + } + } + + + validationSchema() { + const { docPath } = this.props; + + if (docPath) { + const objectKeys = this.objectKeys[docPath + "."]; + if (Array.isArray(objectKeys)) { + // Use the objectKeys from parent fieldset to generate + // actual form fields + const fieldNames = objectKeys.map((fieldName) => { + return `${docPath}.${fieldName}`; + }); + + return this.props.schema.pick(fieldNames).newContext(); + } + } + + return this.props.schema.namedContext(); + } + + get objectKeys() { + return this.props.schema._objectKeys; + } + + get schema() { + return this.props.schema._schema; + } + + valueForField(fieldName) { + const picked = at(this.state.doc, fieldName); + + if (Array.isArray(picked) && picked.length) { + return picked[0]; + } + + return undefined; + } + + validate() { + const { docPath } = this.props; + + // Create a smaller document in order to validate without extra fields + const docToValidate = set( + {}, + docPath, + at(this.state.doc, this.props.docPath)[0] + ); + + // Clean any fields not in schame to avoid needless validation errors + const cleanedObject = this.state.schema._simpleSchema.clean(docToValidate); + + // Finally validate the document + this.setState({ + isValid: this.state.schema.validate(cleanedObject) + }); + } + + isFieldHidden(fieldName) { + if (Array.isArray(this.props.hideFields) && this.props.hideFields.indexOf(fieldName) >= 0) { + return true; + } + + return false; + } + + handleChange = (event, value, name) => { + const newdoc = update(this.state.doc, name, () => { + return value; + }); + + this.setState({ + doc: newdoc + }, () => { + this.validate(); + }); + } + + handleSubmit = (event) => { + event.preventDefault(); + + this.validate(); + + if (this.props.onSubmit) { + this.props.onSubmit(event, { + doc: this.state.doc, + isValid: this.state.isValid + }, this.props.name); + } + } + + renderFormField(field) { + const sharedProps = { + i18nKeyLabel: `settings.${toCamelCase(field.name)}`, + key: field.name, + label: field.label, + name: field.name + }; + + let fieldElement; + let helpText; + + switch (field.type) { + case "boolean": + fieldElement = ( + + ); + break; + case "string": + fieldElement = ( + + ); + break; + default: + return null; + } + + let fieldHasError = false; + + if (this.state.isValid === false) { + this.state.schema._invalidKeys + .filter((v) => v.name === field.name) + .map((validationError) => { + const message = this.state.schema.keyErrorMessage(validationError.name); + fieldHasError = true; + + helpText = ( +
+ {message} +
+ ); + }); + } + + const formGroupClassName = classnames({ + "rui": true, + "form-group": true, + "has-error": fieldHasError + }); + + return ( +
+ {fieldElement} + {helpText} +
+ ); + } + + renderField(field) { + const { fieldName } = field; + + if (this.isFieldHidden(fieldName) === false) { + const fieldSchema = this.schema[fieldName]; + const fieldProps = { + ...fieldSchema, + name: fieldName, + type: typeof fieldSchema.type() + }; + + return this.renderFormField(fieldProps); + } + + return null; + } + + renderWithSchema() { + const { docPath } = this.props; + + if (this.props.schema) { + if (docPath) { + return map(this.schema, (field, key) => { // eslint-disable-line consistent-return + if (key.endsWith(docPath)) { + const objectKeys = this.objectKeys[docPath + "."]; + if (Array.isArray(objectKeys)) { + // Use the objectKeys from parent fieldset to generate + // actual form fields + return objectKeys.map((fieldName) => { + const fullFieldName = docPath ? `${docPath}.${fieldName}` : fieldName; + return this.renderField({ fieldName: fullFieldName }); + }); + } + + return this.renderField({ fieldName: key }); + } + }); + } + + return map(this.schema, (field, key) => { // eslint-disable-line consistent-return + return this.renderField({ fieldName: key }); + }); + } + + return null; + } + + render() { + return ( +
+ {this.renderWithSchema()} + +