2016-11-26 11:33:27 +09:00
/ *
Main form component .
This component expects :
# # # All Forms :
- collection
- currentUser
- client ( Apollo client )
# # # New Form :
- newMutation
# # # Edit Form :
- editMutation
- removeMutation
- document
* /
2017-05-30 09:49:38 +09:00
import { Components , Utils , runCallbacks } from 'meteor/vulcan:core' ;
2017-06-01 10:00:16 +09:00
import React , { Component } from 'react' ;
import PropTypes from 'prop-types' ;
2017-06-01 11:42:30 +09:00
import { FormattedMessage , intlShape } from 'meteor/vulcan:i18n' ;
2016-11-23 17:22:29 +09:00
import Formsy from 'formsy-react' ;
2017-06-02 07:19:39 +09:00
import Button from 'react-bootstrap/lib/Button' ;
2016-11-23 17:22:29 +09:00
import Flash from "./Flash.jsx" ;
import FormGroup from "./FormGroup.jsx" ;
import { flatten , deepValue , getEditableFields , getInsertableFields } from './utils.js' ;
/ *
1. Constructor
2. Helpers
3. Errors
4. Context
4. Method & Callback
5. Render
* /
2016-12-08 23:48:16 +01:00
class Form extends Component {
2016-11-23 17:22:29 +09:00
// --------------------------------------------------------------------- //
// ----------------------------- Constructor --------------------------- //
// --------------------------------------------------------------------- //
constructor ( props ) {
super ( props ) ;
this . submitForm = this . submitForm . bind ( this ) ;
this . updateState = this . updateState . bind ( this ) ;
// this.methodCallback = this.methodCallback.bind(this);
2016-11-25 12:22:13 +09:00
this . newMutationSuccessCallback = this . newMutationSuccessCallback . bind ( this ) ;
this . editMutationSuccessCallback = this . editMutationSuccessCallback . bind ( this ) ;
2016-11-23 17:22:29 +09:00
this . mutationSuccessCallback = this . mutationSuccessCallback . bind ( this ) ;
this . mutationErrorCallback = this . mutationErrorCallback . bind ( this ) ;
this . addToAutofilledValues = this . addToAutofilledValues . bind ( this ) ;
2017-05-06 16:08:01 +09:00
this . addToDeletedValues = this . addToDeletedValues . bind ( this ) ;
2017-06-01 11:50:47 +09:00
this . addToSubmitForm = this . addToSubmitForm . bind ( this ) ;
2017-07-06 12:49:28 -07:00
this . addToSuccessForm = this . addToSuccessForm . bind ( this ) ;
this . addToFailureForm = this . addToFailureForm . bind ( this ) ;
2016-11-23 17:22:29 +09:00
this . throwError = this . throwError . bind ( this ) ;
this . clearForm = this . clearForm . bind ( this ) ;
2017-01-23 15:50:55 +01:00
this . updateCurrentValues = this . updateCurrentValues . bind ( this ) ;
2016-11-23 17:22:29 +09:00
this . formKeyDown = this . formKeyDown . bind ( this ) ;
this . deleteDocument = this . deleteDocument . bind ( this ) ;
2017-06-28 08:50:51 +09:00
this . getDocument = this . getDocument . bind ( this ) ;
2016-11-23 17:22:29 +09:00
// a debounced version of seState that only updates state every 500 ms (not used)
this . debouncedSetState = _ . debounce ( this . setState , 500 ) ;
2017-04-20 16:04:24 +09:00
this . setFormState = this . setFormState . bind ( this ) ;
2016-11-23 17:22:29 +09:00
this . state = {
disabled : false ,
errors : [ ] ,
2017-04-15 21:40:15 +09:00
autofilledValues : props . prefilledProps || { } ,
2017-05-06 16:08:01 +09:00
deletedValues : [ ] ,
2016-11-23 17:22:29 +09:00
currentValues : { }
} ;
2017-05-30 09:49:38 +09:00
this . submitFormCallbacks = [ ] ;
2017-07-06 12:49:28 -07:00
this . successFormCallbacks = [ ] ;
this . failureFormCallbacks = [ ] ;
2016-11-23 17:22:29 +09:00
}
// --------------------------------------------------------------------- //
// ------------------------------- Helpers ----------------------------- //
// --------------------------------------------------------------------- //
// return the current schema based on either the schema or collection prop
getSchema ( ) {
2016-12-12 11:34:28 +09:00
return this . props . schema ? this . props . schema : Utils . stripTelescopeNamespace ( this . props . collection . simpleSchema ( ) . _schema ) ;
2016-11-23 17:22:29 +09:00
}
getFieldGroups ( ) {
const schema = this . getSchema ( ) ;
// build fields array by iterating over the list of field names
let fields = this . getFieldNames ( ) . map ( fieldName => {
// get schema for the current field
const fieldSchema = schema [ fieldName ] ;
fieldSchema . name = fieldName ;
2017-07-06 12:49:28 -07:00
2016-11-23 17:22:29 +09:00
// intialize properties
let field = {
name : fieldName ,
datatype : fieldSchema . type ,
control : fieldSchema . control ,
layout : this . props . layout ,
order : fieldSchema . order
}
2017-07-06 12:49:28 -07:00
// hide or show the field, a function taking form props as argument & returning a boolean can be used
2017-02-08 10:48:17 +01:00
field . hidden = ( typeof fieldSchema . hidden === 'function' ) ? ! ! fieldSchema . hidden . call ( fieldSchema , this . props ) : fieldSchema . hidden ;
2016-11-23 17:22:29 +09:00
// add label or internationalized field name if necessary (field not hidden)
if ( ! field . hidden ) {
2017-05-04 11:16:03 +09:00
field . label = this . context . intl . formatMessage ( { id : this . props . collection . _name + "." + fieldName , defaultMessage : fieldSchema . label } ) ;
2016-11-23 17:22:29 +09:00
}
// add value
field . value = this . getDocument ( ) && deepValue ( this . getDocument ( ) , fieldName ) ? deepValue ( this . getDocument ( ) , fieldName ) : "" ;
2017-05-04 11:16:03 +09:00
// convert value type if needed
if ( fieldSchema . type . definitions [ 0 ] . type === Number ) field . value = Number ( field . value ) ;
2016-12-12 09:55:24 +09:00
// if value is an array of objects ({_id: '123'}, {_id: 'abc'}), flatten it into an array of strings (['123', 'abc'])
2017-01-13 09:21:07 +01:00
// fallback to item itself if item._id is not defined (ex: item is not an object or item is just {slug: 'xxx'})
2016-12-12 09:55:24 +09:00
if ( Array . isArray ( field . value ) ) {
2017-01-13 09:21:07 +01:00
field . value = field . value . map ( item => item . _id || item ) ;
2016-12-12 09:55:24 +09:00
}
2016-11-23 17:22:29 +09:00
// backward compatibility from 'autoform' to 'form'
if ( fieldSchema . autoform ) {
fieldSchema . form = fieldSchema . autoform ;
2017-03-24 10:35:19 +09:00
console . warn ( ` Vulcan Warning: The 'autoform' field is deprecated. You should rename it to 'form' instead. It was defined on your ' ${ fieldName } ' field on the ' ${ this . props . collection . _name } ' collection ` ) ; // eslint-disable-line
2016-11-23 17:22:29 +09:00
}
// replace value by prefilled value if value is empty
if ( fieldSchema . form && fieldSchema . form . prefill ) {
const prefilledValue = typeof fieldSchema . form . prefill === "function" ? fieldSchema . form . prefill . call ( fieldSchema ) : fieldSchema . form . prefill ;
if ( ! ! prefilledValue && ! field . value ) {
field . prefilledValue = prefilledValue ;
field . value = prefilledValue ;
}
}
2016-11-26 02:46:55 +08:00
2016-11-23 17:22:29 +09:00
// replace empty value, which has not been prefilled, by the default value from the schema
if ( fieldSchema . defaultValue && field . value === "" ) {
field . value = fieldSchema . defaultValue ;
}
// add options if they exist
if ( fieldSchema . form && fieldSchema . form . options ) {
field . options = typeof fieldSchema . form . options === "function" ? fieldSchema . form . options . call ( fieldSchema , this . props ) : fieldSchema . form . options ;
}
if ( fieldSchema . form && fieldSchema . form . disabled ) {
field . disabled = typeof fieldSchema . form . disabled === "function" ? fieldSchema . form . disabled . call ( fieldSchema ) : fieldSchema . form . disabled ;
}
if ( fieldSchema . form && fieldSchema . form . help ) {
field . help = typeof fieldSchema . form . help === "function" ? fieldSchema . form . help . call ( fieldSchema ) : fieldSchema . form . help ;
}
2017-06-07 17:59:02 -07:00
// add limit
if ( fieldSchema . limit ) {
field . limit = fieldSchema . limit ;
}
2017-07-06 12:49:28 -07:00
2016-11-23 17:22:29 +09:00
// add placeholder
2017-03-27 10:53:44 +09:00
if ( fieldSchema . placeholder ) {
field . placeholder = fieldSchema . placeholder ;
2016-11-23 17:22:29 +09:00
}
if ( fieldSchema . beforeComponent ) field . beforeComponent = fieldSchema . beforeComponent ;
if ( fieldSchema . afterComponent ) field . afterComponent = fieldSchema . afterComponent ;
// add group
if ( fieldSchema . group ) {
field . group = fieldSchema . group ;
}
// add document
field . document = this . getDocument ( ) ;
return field ;
} ) ;
// remove fields where hidden is set to true
fields = _ . reject ( fields , field => field . hidden ) ;
fields = _ . sortBy ( fields , "order" ) ;
2016-12-12 09:55:24 +09:00
// get list of all unique groups (based on their name) used in current fields
let groups = _ . compact ( _ . unique ( _ . pluck ( fields , "group" ) , false , g => g && g . name ) ) ;
2016-11-23 17:22:29 +09:00
// for each group, add relevant fields
groups = groups . map ( group => {
group . label = group . label || this . context . intl . formatMessage ( { id : group . name } ) ;
group . fields = _ . filter ( fields , field => { return field . group && field . group . name === group . name } ) ;
return group ;
} ) ;
// add default group
groups = [ {
name : "default" ,
label : "default" ,
order : 0 ,
fields : _ . filter ( fields , field => { return ! field . group ; } )
} ] . concat ( groups ) ;
// sort by order
groups = _ . sortBy ( groups , "order" ) ;
// console.log(groups);
return groups ;
}
// if a document is being passed, this is an edit form
getFormType ( ) {
return this . props . document ? "edit" : "new" ;
}
// get relevant fields
getFieldNames ( ) {
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 , this . getDocument ( ) ) : 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 ) ;
}
return relevantFields ;
}
// for each field, we apply the following logic:
// - if its value is currently being inputted, use that
2017-04-15 21:40:15 +09:00
// - else if its value is provided by the autofilledValues object, use that
2016-11-23 17:22:29 +09:00
// - else if its value was provided by the db, use that (i.e. props.document)
getDocument ( ) {
const currentDocument = _ . clone ( this . props . document ) || { } ;
2017-04-15 21:40:15 +09:00
const document = Object . assign ( currentDocument , _ . clone ( this . state . autofilledValues ) , _ . clone ( this . state . currentValues ) ) ;
2016-11-23 17:22:29 +09:00
return document ;
}
// NOTE: this is not called anymore since we're updating on blur, not on change
// whenever the form changes, update its state
updateState ( e ) {
// e can sometimes be event, sometims be currentValue
// see https://github.com/christianalfoni/formsy-react/issues/203
if ( e . stopPropagation ) {
e . stopPropagation ( ) ;
} else {
// get rid of empty fields
_ . forEach ( e , ( value , key ) => {
if ( _ . isEmpty ( value ) ) {
delete e [ key ] ;
}
} ) ;
2017-02-02 15:15:51 +01:00
this . setState ( prevState => ( {
2016-11-23 17:22:29 +09:00
currentValues : e
2017-02-02 15:15:51 +01:00
} ) ) ;
2016-11-23 17:22:29 +09:00
}
}
2017-01-23 15:50:55 +01:00
// manually update the current values of one or more fields(i.e. on blur). See above for on change instead
updateCurrentValues ( newValues ) {
2017-02-02 15:15:51 +01:00
// keep the previous ones and extend (with possible replacement) with new ones
2017-01-23 15:50:55 +01:00
this . setState ( prevState => ( {
2017-02-02 15:15:51 +01:00
currentValues : {
... prevState . currentValues ,
... newValues ,
}
2017-01-23 15:50:55 +01:00
} ) ) ;
2016-11-23 17:22:29 +09:00
}
// key down handler
formKeyDown ( event ) {
if ( ( event . ctrlKey || event . metaKey ) && event . keyCode === 13 ) {
this . submitForm ( this . refs . form . getModel ( ) ) ;
}
}
// --------------------------------------------------------------------- //
// ------------------------------- Errors ------------------------------ //
// --------------------------------------------------------------------- //
// clear and re-enable the form
// by default, clear errors and keep current values
clearForm ( { clearErrors = true , clearCurrentValues = false } ) {
this . setState ( prevState => ( {
errors : clearErrors ? [ ] : prevState . errors ,
currentValues : clearCurrentValues ? { } : prevState . currentValues ,
disabled : false ,
} ) ) ;
}
// render errors
renderErrors ( ) {
2017-07-07 10:21:15 +09:00
return (
< div className = "form-errors" >
{ this . state . errors . map ( ( error , index ) =>
2017-07-19 16:55:51 +09:00
< Flash key = { index } message = { { content : error . message || this . context . intl . formatMessage ( { id : error . name } , error . data ) , type : 'error' } } / >
2017-07-07 10:21:15 +09:00
) }
< / div >
)
2016-11-23 17:22:29 +09:00
}
// --------------------------------------------------------------------- //
// ------------------------------- Context ----------------------------- //
// --------------------------------------------------------------------- //
2017-07-06 12:49:28 -07:00
// add error to form state
2017-02-02 15:15:51 +01:00
// from "GraphQL Error: You have an error [error_code]"
// to { content: "You have an error", type: "error" }
2017-07-07 10:21:15 +09:00
throwError ( error ) {
2017-02-02 15:15:51 +01:00
2017-07-07 10:21:15 +09:00
// get graphQL error (see https://github.com/thebigredgeek/apollo-errors/issues/12)
const graphQLError = error . graphQLErrors [ 0 ] ;
2017-07-06 12:49:28 -07:00
2017-07-07 10:21:15 +09:00
// add error to state
2017-02-02 15:15:51 +01:00
this . setState ( prevState => ( {
2017-07-07 10:21:15 +09:00
errors : [ ... prevState . errors , graphQLError ]
2017-02-02 15:15:51 +01:00
} ) ) ;
2016-11-23 17:22:29 +09:00
}
2017-05-06 16:08:01 +09:00
// add something to autofilled values
2016-11-23 17:22:29 +09:00
addToAutofilledValues ( property ) {
2017-02-02 15:15:51 +01:00
this . setState ( prevState => ( {
autofilledValues : {
... prevState . autofilledValues ,
... property
}
} ) ) ;
2016-11-23 17:22:29 +09:00
}
2017-05-06 16:08:01 +09:00
// add something to deleted values
addToDeletedValues ( name ) {
this . setState ( prevState => ( {
deletedValues : [ ... prevState . deletedValues , name ]
} ) ) ;
}
2017-05-30 09:49:38 +09:00
// add a callback to the form submission
addToSubmitForm ( callback ) {
this . submitFormCallbacks . push ( callback ) ;
}
2017-07-06 12:49:28 -07:00
// add a callback to form submission success
addToSuccessForm ( callback ) {
this . successFormCallbacks . push ( callback ) ;
}
// add a callback to form submission failure
addToFailureForm ( callback ) {
this . failureFormCallbacks . push ( callback ) ;
}
2017-04-20 16:04:24 +09:00
setFormState ( fn ) {
this . setState ( fn ) ;
}
2016-11-23 17:22:29 +09:00
// pass on context to all child components
getChildContext ( ) {
return {
throwError : this . throwError ,
2017-02-02 15:15:51 +01:00
clearForm : this . clearForm ,
2016-11-23 17:22:29 +09:00
autofilledValues : this . state . autofilledValues ,
addToAutofilledValues : this . addToAutofilledValues ,
2017-05-06 16:08:01 +09:00
addToDeletedValues : this . addToDeletedValues ,
2017-01-23 15:50:55 +01:00
updateCurrentValues : this . updateCurrentValues ,
2016-11-23 17:22:29 +09:00
getDocument : this . getDocument ,
2017-04-20 16:04:24 +09:00
setFormState : this . setFormState ,
2017-06-01 11:50:47 +09:00
addToSubmitForm : this . addToSubmitForm ,
2017-07-06 12:49:28 -07:00
addToSuccessForm : this . addToSuccessForm ,
addToFailureForm : this . addToFailureForm ,
2016-11-23 17:22:29 +09:00
} ;
}
// --------------------------------------------------------------------- //
// ------------------------------- Method ------------------------------ //
// --------------------------------------------------------------------- //
2016-11-25 12:22:13 +09:00
newMutationSuccessCallback ( result ) {
this . mutationSuccessCallback ( result , 'new' ) ;
}
editMutationSuccessCallback ( result ) {
this . mutationSuccessCallback ( result , 'edit' ) ;
}
mutationSuccessCallback ( result , mutationType ) {
2016-11-23 17:22:29 +09:00
const document = result . data [ Object . keys ( result . data ) [ 0 ] ] ; // document is always on first property
2016-11-25 12:22:13 +09:00
// for new mutation, run refetch function if it exists
if ( mutationType === 'new' && this . props . refetch ) this . props . refetch ( ) ;
2017-01-13 18:17:08 +01:00
// call the clear form method (i.e. trigger setState) only if the form has not been unmounted (we are in an async callback, everything can happen!)
if ( typeof this . refs . form !== 'undefined' ) {
let clearCurrentValues = false ;
// reset form if this is a new document form
if ( this . props . formType === "new" ) {
this . refs . form . reset ( ) ;
clearCurrentValues = true ;
}
this . clearForm ( { clearErrors : true , clearCurrentValues } ) ;
}
2017-01-10 17:49:03 +09:00
2017-07-06 12:49:28 -07:00
// run document through mutation success callbacks
result = runCallbacks ( this . successFormCallbacks , result ) ;
2016-11-23 17:22:29 +09:00
// run success callback if it exists
if ( this . props . successCallback ) this . props . successCallback ( document ) ;
}
// catch graphql errors
mutationErrorCallback ( error ) {
2017-02-02 15:15:51 +01:00
this . setState ( prevState => ( { disabled : false } ) ) ;
2016-11-23 17:22:29 +09:00
2017-02-02 15:15:51 +01:00
console . log ( "// graphQL Error" ) ; // eslint-disable-line no-console
console . log ( error ) ; // eslint-disable-line no-console
2017-07-06 12:49:28 -07:00
// run mutation failure callbacks on error, we do not allow the callbacks to change the error
runCallbacks ( this . failureFormCallbacks , error ) ;
2016-11-23 17:22:29 +09:00
if ( ! _ . isEmpty ( error ) ) {
// add error to state
2017-07-07 10:21:15 +09:00
this . throwError ( error ) ;
2016-11-23 17:22:29 +09:00
}
// note: we don't have access to the document here :( maybe use redux-forms and get it from the store?
// run error callback if it exists
// if (this.props.errorCallback) this.props.errorCallback(document, error);
}
// submit form handler
submitForm ( data ) {
2017-06-22 16:41:56 +09:00
// if form is disabled (there is already a submit handler running) don't do anything
if ( this . state . disabled ) {
return ;
}
2017-07-06 12:49:28 -07:00
2017-02-02 15:15:51 +01:00
this . setState ( prevState => ( { disabled : true } ) ) ;
2016-11-23 17:22:29 +09:00
// complete the data with values from custom components which are not being catched by Formsy mixin
2016-12-20 09:27:16 +09:00
// note: it follows the same logic as SmartForm's getDocument method
2016-11-26 02:46:55 +08:00
data = {
2017-02-02 15:15:51 +01:00
... this . state . autofilledValues , // ex: can be values from NewsletterSubscribe component
2016-11-23 17:22:29 +09:00
... data , // original data generated thanks to Formsy
... this . state . currentValues , // ex: can be values from DateTime component
} ;
2017-05-30 09:49:38 +09:00
// run data object through submitForm callbacks
data = runCallbacks ( this . submitFormCallbacks , data ) ;
2017-07-06 12:49:28 -07:00
2016-11-23 17:22:29 +09:00
const fields = this . getFieldNames ( ) ;
// if there's a submit callback, run it
if ( this . props . submitCallback ) {
data = this . props . submitCallback ( data ) ;
}
if ( this . props . formType === "new" ) { // new document form
// remove any empty properties
2017-06-20 10:25:34 +09:00
let document = _ . compactObject ( data ) ;
2016-11-23 17:22:29 +09:00
// call method with new document
2016-11-25 12:22:13 +09:00
this . props . newMutation ( { document } ) . then ( this . newMutationSuccessCallback ) . catch ( this . mutationErrorCallback ) ;
2016-11-23 17:22:29 +09:00
} else { // edit document form
const document = this . getDocument ( ) ;
// put all keys with data on $set
2017-06-20 10:25:34 +09:00
const set = _ . compactObject ( data ) ;
2016-11-23 17:22:29 +09:00
// put all keys without data on $unset
2017-05-06 16:08:01 +09:00
const setKeys = _ . keys ( set ) ;
let unsetKeys = _ . difference ( fields , setKeys ) ;
// add all keys to delete (minus those that have data associated)
unsetKeys = _ . unique ( unsetKeys . concat ( _ . difference ( this . state . deletedValues , setKeys ) ) ) ;
2016-11-23 17:22:29 +09:00
2017-05-06 16:08:01 +09:00
// build mutation arguments object
2017-05-07 22:01:52 +09:00
const args = { documentId : document . _id , set : set , unset : { } } ;
2017-05-06 16:08:01 +09:00
if ( unsetKeys . length > 0 ) {
2017-05-07 22:01:52 +09:00
args . unset = _ . object ( unsetKeys , unsetKeys . map ( ( ) => true ) ) ;
2017-05-06 16:08:01 +09:00
}
2016-11-23 17:22:29 +09:00
// call method with _id of document being edited and modifier
2017-05-06 16:08:01 +09:00
this . props . editMutation ( args ) . then ( this . editMutationSuccessCallback ) . catch ( this . mutationErrorCallback ) ;
2016-11-23 17:22:29 +09:00
}
}
deleteDocument ( ) {
const document = this . getDocument ( ) ;
2016-11-25 12:22:13 +09:00
const documentId = this . props . document . _id ;
2016-11-27 08:39:25 +09:00
const documentTitle = document . title || document . name || '' ;
2016-11-23 17:22:29 +09:00
2017-03-18 15:59:31 +09:00
const deleteDocumentConfirm = this . context . intl . formatMessage ( { id : 'forms.delete_confirm' } , { title : documentTitle } ) ;
2016-11-23 17:22:29 +09:00
2016-12-08 23:48:16 +01:00
if ( window . confirm ( deleteDocumentConfirm ) ) {
2016-11-23 17:22:29 +09:00
this . props . removeMutation ( { documentId } )
. then ( ( mutationResult ) => { // the mutation result looks like {data:{collectionRemove: null}} if succeeded
2016-11-24 15:47:51 +09:00
if ( this . props . removeSuccessCallback ) this . props . removeSuccessCallback ( { documentId , documentTitle } ) ;
2016-11-25 12:22:13 +09:00
if ( this . props . refetch ) this . props . refetch ( ) ;
2016-11-23 17:22:29 +09:00
} )
2016-11-24 15:47:51 +09:00
. catch ( ( error ) => {
console . log ( error ) ;
2016-11-23 17:22:29 +09:00
} ) ;
}
}
// --------------------------------------------------------------------- //
// ------------------------- Lifecycle Hooks --------------------------- //
// --------------------------------------------------------------------- //
render ( ) {
const fieldGroups = this . getFieldGroups ( ) ;
const collectionName = this . props . collection . _name ;
return (
< div className = { "document-" + this . props . formType } >
< Formsy.Form
onSubmit = { this . submitForm }
onKeyDown = { this . formKeyDown }
disabled = { this . state . disabled }
ref = "form"
>
{ this . renderErrors ( ) }
2017-01-23 15:50:55 +01:00
{ fieldGroups . map ( group => < FormGroup key = { group . name } { ...group } updateCurrentValues = { this . updateCurrentValues } / > ) }
2017-07-06 12:49:28 -07:00
2017-06-01 11:50:47 +09:00
< div className = "form-submit" >
< Button type = "submit" bsStyle = "primary" > { this . props . submitLabel ? this . props . submitLabel : < FormattedMessage id = "forms.submit" / > } < / Button >
{ this . props . cancelCallback ? < a className = "form-cancel" onClick = { this . props . cancelCallback } > { this . props . cancelLabel ? this . props . cancelLabel : < FormattedMessage id = "forms.cancel" / > } < / a > : null }
< / div >
2016-11-23 17:22:29 +09:00
< / Formsy.Form >
{
this . props . formType === 'edit' && this . props . showRemove
? < div >
< hr / >
< a onClick = { this . deleteDocument } className = { ` ${ collectionName } -delete-link ` } >
2017-03-18 15:59:31 +09:00
< Components.Icon name = "close" / > < FormattedMessage id = "forms.delete" / >
2016-11-23 17:22:29 +09:00
< / a >
< / div >
: null
}
< / div >
)
}
}
2016-12-08 23:48:16 +01:00
Form . propTypes = {
2016-11-23 17:22:29 +09:00
// main options
2017-02-02 15:15:51 +01:00
collection : PropTypes . object ,
document : PropTypes . object , // if a document is passed, this will be an edit form
schema : PropTypes . object , // usually not needed
2016-11-23 17:22:29 +09:00
// graphQL
2017-02-02 15:15:51 +01:00
newMutation : PropTypes . func , // the new mutation
editMutation : PropTypes . func , // the edit mutation
removeMutation : PropTypes . func , // the remove mutation
2016-11-23 17:22:29 +09:00
// form
2017-02-02 15:15:51 +01:00
prefilledProps : PropTypes . object ,
layout : PropTypes . string ,
fields : PropTypes . arrayOf ( PropTypes . string ) ,
showRemove : PropTypes . bool ,
2017-06-01 11:50:47 +09:00
submitLabel : PropTypes . string ,
cancelLabel : PropTypes . string ,
2016-11-23 17:22:29 +09:00
// callbacks
2017-02-02 15:15:51 +01:00
submitCallback : PropTypes . func ,
successCallback : PropTypes . func ,
removeSuccessCallback : PropTypes . func ,
errorCallback : PropTypes . func ,
cancelCallback : PropTypes . func ,
currentUser : PropTypes . object ,
client : PropTypes . object ,
2016-11-23 17:22:29 +09:00
}
2016-12-08 23:48:16 +01:00
Form . defaultProps = {
2016-11-23 17:22:29 +09:00
layout : "horizontal" ,
}
2016-12-08 23:48:16 +01:00
Form . contextTypes = {
2016-11-23 17:22:29 +09:00
intl : intlShape
}
2016-12-08 23:48:16 +01:00
Form . childContextTypes = {
2017-02-02 15:15:51 +01:00
autofilledValues : PropTypes . object ,
addToAutofilledValues : PropTypes . func ,
2017-05-06 16:08:01 +09:00
addToDeletedValues : PropTypes . func ,
2017-05-30 09:49:38 +09:00
addToSubmitForm : PropTypes . func ,
2017-07-06 12:49:28 -07:00
addToFailureForm : PropTypes . func ,
addToSuccessForm : PropTypes . func ,
2017-02-02 15:15:51 +01:00
updateCurrentValues : PropTypes . func ,
2017-04-20 16:04:24 +09:00
setFormState : PropTypes . func ,
2017-02-02 15:15:51 +01:00
throwError : PropTypes . func ,
clearForm : PropTypes . func ,
getDocument : PropTypes . func
2016-11-23 17:22:29 +09:00
}
2016-12-08 23:48:16 +01:00
module . exports = Form