/*
Generate the appropriate fragment for the current form, then
wrap the main Form component with the necessary HoCs while passing
them the fragment.
This component is itself wrapped with:
- withCurrentUser
- withApollo (used to access the Apollo client for form pre-population)
And wraps the Form component with:
- withNew
Or:
- withSingle
- withEdit
- withRemove
(When wrapping with withSingle, withEdit, and withRemove, a special Loader
component is also added to wait for withSingle's loading prop to be false)
*/
import Telescope from 'meteor/nova:lib';
import React, { PropTypes, Component } from 'react';
import { intlShape } from 'react-intl';
import { withApollo, compose } from 'react-apollo';
import { withCurrentUser } from 'meteor/nova:users';
import { withNew, withEdit, withRemove } from 'meteor/nova:core';
import { getEditableFields, getInsertableFields } from './utils.js';
import Form from './Form.jsx';
import gql from 'graphql-tag';
import { withSingle } from 'meteor/nova:core';
class FormWithSingle extends Component{
// return the current schema based on either the schema or collection prop
getSchema() {
return this.props.schema ? this.props.schema : Telescope.utils.stripTelescopeNamespace(this.props.collection.simpleSchema()._schema);
}
// if a document is being passed, this is an edit form
getFormType() {
return this.props.documentId ? "edit" : "new";
}
// get fragment used to decide what data to load from the server to populate the form,
// as well as what data to ask for as return value for the mutation
getFragment() {
const prefix = `${this.props.collection._name}${Telescope.utils.capitalize(this.getFormType())}`
const fragmentName = `${prefix}FormFragment`;
const fields = this.props.fields;
// get all editable/insertable fields (depending on current form type)
let relevantFields = this.getFormType() === 'edit' ? getEditableFields(this.getSchema(), this.props.currentUser) : getInsertableFields(this.getSchema(), this.props.currentUser);
// if "fields" prop is specified, restrict list of fields to it
if (typeof fields !== "undefined" && fields.length > 0) {
relevantFields = _.intersection(relevantFields, fields);
}
// fields with resolvers that contain "[" should be treated as arrays of _ids
// TODO: find a cleaner way to handle this
relevantFields = relevantFields.map(fieldName => {
const resolveAs = this.getSchema()[fieldName].resolveAs;
return resolveAs && resolveAs.indexOf('[') > -1 ? `${fieldName}{_id}` : fieldName;
});
// generate fragment based on the fields that can be edited. Note: always add _id.
const fragment = `fragment ${fragmentName} on ${this.props.collection.typeName} {
_id
${relevantFields.join('\n')}
}`
return gql`${fragment}`;
}
// prevent extra re-renderings for unknown reasons
shouldComponentUpdate() {
return false;
}
render() {
let WrappedComponent;
const prefix = `${this.props.collection._name}${Telescope.utils.capitalize(this.getFormType())}`
const queryName = `${prefix}FormQuery`;
const fragmentName = `${prefix}FormFragment`;
// props received from parent component (i.e.