UNPKG

@onereach/webform

Version:

Content Builder includes several views for: - Content builder view itself; - Web Form view; - Slack block-kit builder;

418 lines (359 loc) 10.9 kB
import Vue from 'vue'; import itemsData from '@/data/contentBuilderFields.json'; import { v4 as uuid } from 'uuid'; import EventBus from '@/helpers/eventBus'; // helpers for testing transform functions between generic and specific channel // uncomment if you need to test transformation /* import { parseSlackMrkdwnToMarkdown, transformGenericToSlack } from '@onereach/channel-transformer'; console.log("transformGenericToSlack -> ", transformGenericToSlack); */ import { OUTPUT_SET_GENERIC, OUTPUT_SET_CB_SCHEMA, OUTPUT_SET_LOADING, OUTPUT_RESET_GENERIC_MODEL, OUTPUT_SET_GENERIC_FIELD, OUTPUT_SET_GENERIC_FIELD_VALUE, OUTPUT_DELETE_GENERIC_FIELD, OUTPUT_SET_ERROR, OUTPUT_CLEAR_ERROR, OUTPUT_SET_GENERIC_CHILDREN, OUTPUT_SET_WRAPPER_PROP, OUTPUT_SET_CHANNEL, OUTPUT_SET_GENERIC_HEIGHT_OF_WEB_PREVIEW, OUTPUT_SET_STEP_SCHEMA } from '../mutation-types'; const defaultGenericModel = { type: 'wrapper', children: [], props: { slack: { type: 'modal', title: { type: 'text', props: { value: 'My App', slack: { type: 'plain_text', emoji: true, verbatim: false } } }, submit: { type: 'text', props: { value: 'Submit', slack: { type: 'plain_text', emoji: true, verbatim: false } } }, close: { type: 'text', props: { value: 'Cancel', slack: { type: 'plain_text', emoji: true, verbatim: false } } } } } }; /* const state = { fieldsList: itemsData, error: '', invalidFields: {}, currentChannel: 'web', genericModel: defaultGenericModel, slackType: null, hasInteractive: false, isGenericMode: false, loading: true, stepId: '', readonly: false, steps: [], mergeFields: [], isNew: true, authToken: null, filesApiUrl: null, schema: null }; */ const getters = { getFieldsList: (state) => state.fieldsList[state.currentChannel], genericModelChildren: (state) => { if (state.genericModel && state.genericModel.children) { if (Array.isArray(state.genericModel.children)) { const sectionIds = []; // track section ids to prevent two sections have the same id, f.e. in case of copying state.genericModel.children.forEach((child) => { if (child && typeof child === 'object') { child.id = !child.id || sectionIds.includes(child.id) ? uuid() : child.id; sectionIds.push(child.id); child.parentId = child.id || uuid(); // child.active = child.active || false; child.editMode = child.editMode || false; if (Array.isArray(child.children)) { return child.children.forEach((children) => { if (children && typeof children === 'object') { children.parentId = child.id || uuid(); children.id = children.id || uuid(); // children.active = children.active || false; children.editMode = children.editMode || false; } }); } } }); return state.genericModel.children || []; } else { return state.genericModel.children; } } }, getGenericDataValue: (state) => ({ id, path }) => { const field = _.cloneDeep( state.genericModel.children.filter((field) => field.id === id)[0] ); return path ? _.get(field, path) : field; }, getGenericWrapperPropsValue: (state) => ({ path }) => { return _.get(state.genericModel.props, path); }, getSchemaValue: (state) => (path) => _.get(state.schema, path) }; const actions = { async initialize ({ dispatch }) { dispatch('initCrossWindowCommunication'); }, sendMessage ({ state }) { // console.log('sendMesssage state -> ', state); const invalidFieldsParsed = window.localStorage.getItem('invalidFields') && JSON.parse(window.localStorage.getItem('invalidFields')); // console.log('invalidFieldsParsed -> ', invalidFieldsParsed); const postedData = { eventType: 'set-form-data', invalid: false, dataOut: JSON.stringify(state.genericModel) }; if (invalidFieldsParsed && Object.keys(invalidFieldsParsed).length) { postedData.invalid = true; } window.parent.postMessage(postedData, '*'); }, initCrossWindowCommunication ({ commit, state }) { if (!window) { return commit(OUTPUT_SET_LOADING, false); } if (!window && process.env.NODE_ENV === 'development') { commit(OUTPUT_SET_LOADING, false); } const handleMessage = (e) => { let { data } = e; if ( !data || typeof data !== 'string' || _.includes(data, 'webpackHotUpdate') || data.type === 'webpackOk' ) { return; } data = JSON.parse(data); if (data.eventType === 'set-initial-data') { const dataOut = _.get(data, 'dataOut', {}); commit( OUTPUT_SET_GENERIC, _.get(dataOut, 'schema.formData.value'), state.genericModel ); commit(OUTPUT_SET_CB_SCHEMA, dataOut); EventBus.$emit('store:set-initial-data', dataOut); } // Data for preview instance if (data.eventType === 'set-preview-data') { commit(OUTPUT_SET_GENERIC, data.generic || {}); commit(OUTPUT_SET_STEP_SCHEMA, data.schema || {}); } if (data.eventType === 'update-preview-data') { // updates schema only // commit(OUTPUT_SET_GENERIC, data.generic || {}); commit(OUTPUT_SET_STEP_SCHEMA, data.schema || {}); } }; const tHandler = _.throttle(handleMessage, 300); window.addEventListener('message', tHandler); window.parent.postMessage({ eventType: 'get-initial-data' }, '*'); commit(OUTPUT_SET_LOADING, false); }, setOutputValue ({ dispatch, commit }, payload) { if (payload) { commit(OUTPUT_SET_GENERIC_FIELD_VALUE, payload); } dispatch('sendMessage'); }, deleteField ({ dispatch, commit }, id) { commit(OUTPUT_DELETE_GENERIC_FIELD, id); commit(OUTPUT_CLEAR_ERROR, id); dispatch('sendMessage'); } }; const mutations = { [OUTPUT_SET_CHANNEL] (state, payload) { state.currentChannel = payload; }, [OUTPUT_SET_CB_SCHEMA] (state, dataOut) { const { slackType, hasInteractive, formBuilderType, stepId, readonly, steps, mergeFields, isNew, authToken, filesApiUrl, hideInputs, schema } = dataOut; if (_.get(schema, 'formData.value')) { state.genericModel = _.get(schema, 'formData.value'); } state.currentChannel = formBuilderType || 'web'; state.slackType = slackType; state.hideInputs = hideInputs || false; state.hasInteractive = hasInteractive; state.stepId = stepId || ''; state.readonly = readonly || false; state.steps = steps || []; state.mergeFields = mergeFields || []; state.isNew = isNew || false; state.authToken = authToken; state.filesApiUrl = filesApiUrl; state.schema = schema; }, [OUTPUT_SET_LOADING] (state, payload) { state.loading = payload; }, [OUTPUT_SET_GENERIC] (state, payload) { if (_.isArray(payload) || typeof payload === 'string' || !payload) return; state.genericModel = payload; // helpers for testing transform functions between generic and specific channel // uncomment if you need to test transformation /* console.log( 'transform pure -> ', transformGenericToSlack(state.genericModel) ); console.log( 'transform stringified -> ', JSON.stringify( transformGenericToSlack(state.genericModel) ) ); */ }, [OUTPUT_SET_GENERIC_CHILDREN] (state, payload) { if (!Array.isArray(payload)) return; if (!payload.length) { const stringified = JSON.stringify({}); window.localStorage.setItem('invalidFields', stringified); } state.genericModel.children = payload; }, [OUTPUT_RESET_GENERIC_MODEL] (state) { state.genericModel = defaultGenericModel; }, [OUTPUT_SET_GENERIC_FIELD] (state, payload) { if (!state.genericModel.children) { state.genericModel = defaultGenericModel; } state.genericModel.children.push(payload); }, [OUTPUT_DELETE_GENERIC_FIELD] (state, id) { if (isNaN(id)) { state.genericModel.children = state.genericModel.children.filter( (item) => item.id !== id ); } else { const index = parseInt(id); state.genericModel.children.splice(index, 1); } }, [OUTPUT_SET_GENERIC_HEIGHT_OF_WEB_PREVIEW] (state, height) { if (!state.genericModel.props) { state.genericModel.props = {}; } state.genericModel.props.webFormHeight = height; }, [OUTPUT_SET_GENERIC_FIELD_VALUE] (state, payload) { const { id, path, value } = payload; const field = _.cloneDeep( state.genericModel.children.filter((field) => field.id === id) )[0]; const index = state.genericModel.children.findIndex( (field) => field.id === id ); const res = path ? _.set(field, path, value) : value; Vue.set(state.genericModel.children, index, res); }, [OUTPUT_SET_WRAPPER_PROP] (state, payload) { const { path, value } = payload; const props = _.cloneDeep(state.genericModel.props); const res = _.set(props, path, value); Vue.set(state.genericModel, 'props', res); }, // TODO: for future errors hendling [OUTPUT_SET_ERROR] (state, schema) { /* schema -> Object {id: true|false} */ state.invalidFields[schema.id] = schema.invalid; const stringified = JSON.stringify(state.invalidFields); window.localStorage.setItem('invalidFields', stringified); }, [OUTPUT_CLEAR_ERROR] (state, schema) { if (state.invalidFields[schema.id]) { delete state.invalidFields[schema.id]; } const stringified = JSON.stringify(state.invalidFields); window.localStorage.setItem('invalidFields', stringified); }, [OUTPUT_SET_STEP_SCHEMA] (state, payload) { state.schema = payload; } }; export default { namespaced: true, state () { return { fieldsList: itemsData, error: '', invalidFields: {}, validation: { $invalid: false }, currentChannel: 'web', genericModel: defaultGenericModel, slackType: null, hasInteractive: false, isGenericMode: false, loading: true, stepId: '', readonly: false, steps: [], mergeFields: [], isNew: true, authToken: null, filesApiUrl: null, schema: null }; }, getters, actions, mutations };