import React from "react" ; import shortid from "shortid" ; import { cloneDeep , pick } from "lodash" ; import { GET_FORM , UPDATE_REVISION } from "./graphql" ; import { getFieldPosition , moveField , moveRow , deleteField } from "./functions" ; import { plugins } from "@webiny/plugins" ; import { FbFormModelFieldsLayout , FbFormModelField , FieldIdType , FieldLayoutPositionType , FbBuilderFieldPlugin } from "../../../../types" ; export default FormEditorContext => { return ( ) => { const context = React . useContext < any > ( FormEditorContext ) ; if ( ! context ) { throw new Error ( "useFormEditor must be used within a FormEditorProvider" ) ; } const { state , dispatch } = context ; const self = { apollo : state . apollo , data : state . data , state , async getForm ( id ) { const response = await self . apollo . query ( { query : GET_FORM , variables : { revision : decodeURIComponent ( id ) } } ) ; const { data , error } = response ?. data ?. formBuilder ?. getForm || { } ; if ( error ) { throw new Error ( error ) ; } self . setData ( ( ) => { const form = cloneDeep ( data ) ; if ( ! form . settings . layout . renderer ) { form . settings . layout . renderer = state . defaultLayoutRenderer ; } return form ; } , false ) ; return response ; } , saveForm : async ( data ) => { data = data || state . data ; const response = await self . apollo . mutate ( { mutation : UPDATE_REVISION , variables : { revision : decodeURIComponent ( data . id ) , data : pick ( data , [ "layout" , "fields" , "name" , "settings" , "triggers" ] ) } } ) ; return response ?. data ?. formBuilder ?. updateRevision ; } , param setter param saveForm setData ( setter , saveForm = true ) { const data = setter ( cloneDeep ( self . data ) ) ; dispatch ( { type : "data" , data } ) ; saveForm !== false && self . saveForm ( data ) ; } , param layout returns { * } getFields ( layout = false ) { if ( ! layout ) { return state . data . fields ; } const fields = cloneDeep ( state . data . layout ) ; fields . forEach ( ( row , rowIndex ) => { row . forEach ( ( fieldId , fieldIndex ) => { fields [ rowIndex ] [ fieldIndex ] = self . getField ( { _id : fieldId } ) ; } ) ; } ) ; return fields ; } , param query returns { void | ? FbFormModelField } getFieldPlugin ( query ) { return plugins . byType < FbBuilderFieldPlugin > ( "form-editor-field-type" ) . find ( ( { field } ) => { for ( const key in query ) { if ( ! ( key in field ) ) { return null ; } if ( field [ key ] !== query [ key ] ) { return null ; } } return true ; } ) ; } , param query returns { boolean } getField ( query ) { return state . data . fields . find ( field => { for ( const key in query ) { if ( ! ( key in field ) ) { return null ; } if ( field [ key ] !== query [ key ] ) { return null ; } } return true ; } ) ; } , param data param position insertField ( data , position ) { const field = cloneDeep ( data ) ; if ( ! field . _id ) { field . _id = shortid . generate ( ) ; } if ( ! data . name ) { throw new Error ( `Field "name" missing.` ) ; } const fieldPlugin = self . getFieldPlugin ( { name : data . name } ) ; if ( ! fieldPlugin ) { throw new Error ( `Invalid field "name".` ) ; } data . type = fieldPlugin . field . type ; self . setData ( data => { if ( ! Array . isArray ( data . fields ) ) { data . fields = [ ] ; } data . fields . push ( field ) ; moveField ( { field , position , data } ) ; return data ; } ) ; } , param field param position param data moveField ( { field , position } ) { self . setData ( data => { moveField ( { field , position , data } ) ; return data ; } ) ; } , param source param destination moveRow ( source , destination ) { self . setData ( data => { moveRow ( { data , source , destination } ) ; return data ; } ) ; } , param fieldData updateField ( fieldData ) { const field = cloneDeep ( fieldData ) ; self . setData ( data => { for ( let i = 0 ; i < data . fields . length ; i ++ ) { if ( data . fields [ i ] . _id === field . _id ) { data . fields [ i ] = field ; break ; } } return data ; } ) ; } , param field deleteField ( field ) { self . setData ( data => { deleteField ( { field , data } ) ; return data ; } ) ; } , param field returns { { index : number , row : number } | { index : null , row : null } } getFieldPosition ( field ) { return getFieldPosition ( { field , data : self . data } ) ; } } ; return self ; } ; } ;