GrapesJS / components-custom-code

GrapesJS component for the embed of custom code
https://grapesjs.com/demo.html
BSD 3-Clause "New" or "Revised" License
74 stars 45 forks source link

grapejs-custom-code is not loaded. #25

Closed alexjoe118 closed 1 year ago

alexjoe118 commented 1 year ago

Hi guys. I developed a website using grapejs. I tried to use plugin grapejs-custom-code in my project. The Installation was success. And also it works on my local. But after deploying on server, the custom code element doesn't appear in category menu. and I couldn't use it. I wonder if there is some settings on that I don't know. I can't understand that's why. Please help me. my package.json is as follow.

{ "name": "frontend", "version": "0.1.0", "private": true, "dependencies": { "@babel/core": "7.1.6", "@date-io/date-fns": "^1.3.9", "@material-ui/core": "^4.3.3", "@material-ui/pickers": "^3.2.3", "@svgdotjs/svg.js": "^3.0.16", "@svgr/webpack": "2.4.1", "app-module-path": "^2.2.0", "axios": "^0.18.0", "babel-core": "7.0.0-bridge.0", "babel-jest": "^24.5.0", "babel-loader": "8.0.4", "babel-plugin-named-asset-import": "^0.3.0", "babel-preset-react-app": "^7.0.0", "bfj": "6.1.1", "case-sensitive-paths-webpack-plugin": "2.1.2", "chalk": "2.4.1", "chart.js": "^2.7.3", "css-loader": "1.0.0", "date-fns": "^2.0.0-beta.5", "dom-to-image": "^2.6.0", "dotenv": "6.0.0", "dotenv-expand": "4.2.0", "fastpanel-api": "0.0.7", "file-loader": "2.0.0", "fork-ts-checker-webpack-plugin-alt": "0.4.14", "fs-extra": "7.0.0", "grapesjs": "^0.20.1", "grapesjs-blocks-basic": "^1.0.1", "grapesjs-component-countdown": "^1.0.1", "grapesjs-custom-code": "^1.0.1", "grapesjs-navbar": "^1.0.1", "grapesjs-plugin-export": "^1.0.11", "grapesjs-plugin-forms": "^2.0.5", "grapesjs-preset-webpage": "^1.0.2", "grapesjs-react": "^4.0.1", "grapesjs-tabs": "^1.0.6", "html-to-image": "^1.10.8", "html-webpack-plugin": "4.0.0-alpha.2", "html2canvas": "^1.4.1", "identity-obj-proxy": "3.0.0", "immutable": "^4.0.0-rc.12", "jest": "^24.5.0", "jest-pnp-resolver": "1.0.1", "jest-resolve": "23.6.0", "jodit-react": "^1.0.59", "js-cookie": "^2.2.1", "luxon": "^1.25.0", "mini-css-extract-plugin": "0.4.3", "moment": "^2.24.0", "moment-timezone": "^0.5.32", "node-sass": "^4.14.1", "nodemon": "^2.0.20", "optimize-css-assets-webpack-plugin": "5.0.1", "pnp-webpack-plugin": "1.1.0", "postcss-flexbugs-fixes": "4.1.0", "postcss-loader": "3.0.0", "postcss-preset-env": "6.3.1", "postcss-safe-parser": "4.0.1", "ramda": "^0.26.1", "react": "^16.14.0", "react-app-polyfill": "^0.2.0", "react-circular-progressbar": "^2.0.4", "react-confirm-alert": "^2.8.0", "react-copy-text": "^1.0.1", "react-day-picker": "^7.3.0", "react-dev-utils": "^7.0.1", "react-dom": "^16.14.0", "react-drag-drop-files": "^2.3.7", "react-html-parser": "^2.0.2", "react-image-crop": "^10.0.8", "react-json-view": "^1.19.1", "react-redux": "^7.1.3", "react-router-dom": "^4.3.1", "react-scripts": "^2.1.8", "react-toastify": "^4.5.2", "react-uploader": "^2.1.0", "recharts": "^2.0.3", "recompose": "^0.30.0", "redux": "^4.0.1", "redux-thunk": "^2.3.0", "reselect": "^4.0.0", "resolve": "1.8.1", "sass-loader": "7.1.0", "semantic-ui-css": "2.4.1", "semantic-ui-react": "0.84.0", "style-loader": "0.23.0", "terser-webpack-plugin": "1.1.0", "title-case": "^2.1.1", "twilio-client": "^1.12.5", "url-loader": "1.1.1", "webpack": "4.19.1", "webpack-dev-server": "3.1.14", "webpack-manifest-plugin": "2.0.4", "workbox-webpack-plugin": "3.6.3" }, "scripts": { "start": "node scripts/start.js", "build": "node scripts/build.js", "test": "node scripts/test.js" }, "eslintConfig": { "extends": "react-app" }, "browserslist": [ ">0.2%", "not dead", "not ie <= 11", "not op_mini all" ], "jest": { "collectCoverageFrom": [ "src//*.{js,jsx,ts,tsx}", "!src/*/.d.ts" ], "resolver": "jest-pnp-resolver", "setupFiles": [ "react-app-polyfill/jsdom" ], "testMatch": [ "/src//tests/*/.{js,jsx,ts,tsx}", "/src/*/?(.)(spec|test).{js,jsx,ts,tsx}" ], "testEnvironment": "jsdom", "testURL": "http://localhost", "transform": { "^.+\.(js|jsx|ts|tsx)$": "/node_modules/babel-jest", "^.+\.css$": "/config/jest/cssTransform.js", "^(?!.*\.(js|jsx|ts|tsx|css|json)$)": "/config/jest/fileTransform.js" }, "transformIgnorePatterns": [ "[/\\]node_modules[/\\].+\.(js|jsx|ts|tsx)$", "^.+\.module\.(css|sass|scss)$" ], "moduleNameMapper": { "^react-native$": "react-native-web", "^.+\.module\.(css|sass|scss)$": "identity-obj-proxy" }, "moduleFileExtensions": [ "web.js", "js", "web.ts", "ts", "web.tsx", "tsx", "json", "web.jsx", "jsx", "node" ], "moduleDirectories": [ "node_modules", "src" ] }, "babel": { "presets": [ "react-app" ] }, "devDependencies": { "babel-eslint": "^9.0.0", "eslint": "^5.6.0", "eslint-config-airbnb": "^17.1.0", "eslint-config-react-app": "^3.0.8", "eslint-loader": "^2.1.2", "eslint-plugin-import": "^2.16.0", "eslint-plugin-jsx-a11y": "^6.2.1", "eslint-plugin-react": "^7.12.4", "husky": "^1.3.1", "lint-staged": "^8.1.4", "ngrok": "^3.2.5" }, "engines": { "node": "v8.17.0", "npm": "6.13.4" } }

and my code using custom code element.

import React, { Component } from 'react'; import { compose } from 'recompose'; import { BuildContainer, BuildFormContainer, MessagesContainer, DealsContainer, CampaignsContainer } from '@containers'; import BuildModal from '../@common/modals/builder';

import { Button, Icon, Dropdown, Popup, Modal } from 'semantic-ui-react'; import Loader from '../loader';

import grapesjs from 'grapesjs'; import plugin from 'grapesjs-preset-webpage'; import basic from 'grapesjs-blocks-basic'; import forms from 'grapesjs-plugin-forms'; import pgexport from 'grapesjs-plugin-export'; import navbar from 'grapesjs-navbar'; import countdown from 'grapesjs-component-countdown'; import tabs from 'grapesjs-tabs'; import customcode from 'grapesjs-custom-code';

import 'grapesjs/dist/css/grapes.min.css'; import defaultPage from './default'; import './grapes.css'; import './index.scss'; import history from '../../history'; import { config } from "@services";

import * as htmlToImage from 'html-to-image'; import { indexOf } from "ramda"; const svgNameList = ['column', '2columns', '3columns', '2col37', 'text', 'link', 'image', 'video', 'map', 'linkblock', 'quote', 'textsection', 'form', 'input', 'textarea', 'select', 'button', 'label', 'checkbox', 'radio', 'navbar', 'countdown', 'tabs', 'customcode' ];

const panelList = []; panelList[0] = []; panelList[1] = ['ti ti-device-desktop', 'ti ti-device-tablet', 'ti ti-device-mobile']; panelList[2] = ['ti ti-marquee-2', '', 'ti ti-arrows-maximize', 'ti ti-code', '', '', 'ti ti-file-import', 'ti ti-eraser']; panelList[3] = ['ti ti-pencil', 'ti ti-settings', 'ti ti-layers-subtract', 'ti ti-layout-grid'];

class Builder extends Component { state = { editor: {}, pages: [], preview: true, selPage: parseInt(localStorage.getItem('page_id')), zIndex: 4, show: false, pindex: 0, };

componentDidMount() {
    this.props.init();
    let editor = grapesjs.init({
        fromElement: true,
        container: '#gjs',
        storageManager: {
            type: 'local',
            autoload: true,
            autosave: true,
            stepsBeforeSave: 1,
            storeComponents: true,
            storeStyles: true,
            storeHtml: true,
            storeCss: true,
            autorender: false
        },
        plugins: [
            basic, plugin, forms, pgexport, navbar, countdown, tabs, customcode,
        ],
        pluginsOpts: {
            [pgexport]: {
                addExportBtn: true,
                btnLabel: 'export',
                css: {
                    'style.css': ed => ed.getCss(),
                    'some-file.txt': 'My custom content',
                },
                img: async ed => {
                    const images = await ed.getComponents();
                    return images;
                },
                'index.html': ed => `<body>${ed.getHtml()}</body>`
            },
            [countdown]: { /* options */ },
            [tabs]:{
                tabsBlock: {
                    category: 'Extra'
                  }
            },
            [customcode]:{
                'blockCustomCode':'EXTRA',
            },

        },

    });

    const fontManager = editor.StyleManager.getProperty('typography', 'font-family');
    let fontOptions = fontManager.attributes.options;
    //add typography fonts
    fontOptions.push({ value: 'Roboto, Arial', name: 'Roboto' });
    fontOptions.push({ value: 'Open Sans', name: 'Open Sans' });
    fontOptions.push({ value: 'Lato', name: 'Lato' });
    fontOptions.push({ value: 'Montserrat', name: 'Montserrat' });
    fontOptions.push({ value: 'Oswald', name: 'Oswald' });
    fontOptions.push({ value: 'Source Sans Pro', name: 'Source Sans Pro' });
    fontOptions.push({ value: 'Slabo', name: 'Slabo' });
    fontOptions.push({ value: 'Raleway', name: 'Raleway' });
    fontOptions.push({ value: 'Poppins', name: 'Poppins' });
    fontOptions.push({ value: 'Josefin Sans', name: 'Josefin Sans' });
    fontOptions.push({ value: 'Nunito', name: 'Nunito' });

    const panelManager = editor.Panels;
    let panels = panelManager.getPanels();

    panels.map((panel, index) => {
        panel.buttons.models.map((button, pindex) => {
            button.set('label', '');
            button.set('className', panelList[index][pindex]);
        })
        panels[index] = panel;
    });

    const blockManager = editor.Blocks;
    let blocks = blockManager.getAll();

    blocks.map((block, index) => {
        block.attributes.media = '<img src = "buildericons/' + svgNameList[index] + '.svg">';
        blocks[index] = block;
        if (block.attributes.label === "Form") {
            const formComponent = [
                { components: [{ type: 'label', components: 'Name' }, { type: 'input', attributes: { name: 'fullname' } }] },
                { components: [{ type: 'label', components: 'Email' }, { type: 'input', attributes: { type: 'email', name: 'email' } }] },
                { components: [{ type: 'label', components: 'Phone' }, { type: 'input', attributes: { name: 'phone' } }] },
                { type: 'button', attributes: { type: 'submit' } }
            ];
            block.attributes.content.components = formComponent;
        }
    });
    blockManager.render(blocks);

    var _self = this;

    editor.DomComponents.addType('form', {
        isComponent: el => el.tagName === 'FORM',
        model: {
            init() {
            },
            defaults: {
                traits: [{
                    type: 'checkbox',
                    name: 'integration',
                    label: 'Send to integration',
                }
                ],
                // attributes: { type: 'text', required: true },
            },
        },
        view: {
            init() {
                this.listenTo(this.model, 'change:attributes:integration', this.changeIntegration);
                this.listenTo(this.model, 'change:attributes:campaign', this.changeCampaign);
                this.listenTo(this.model, 'change:attributes:redirect_checkbox', this.changeRedirect);
            },
            changeIntegration() {
                // this.model.setAttributes({...this.model.attributes,method:'post'});
                this.model.attributes.attributes.method = 'post';
                this.changeTrait();
                const properties = this.model.attributes.attributes;
                if (properties.integration) {
                    _self.props.getCompanyDeals();
                    if (properties.campaign) {
                        let companyId = properties.campaign.split('_')[0];
                        let dealId = properties.campaign.split('_')[1];
                        _self.props.loadDealCampaigns(companyId, dealId);
                    }
                }
            },
            changeCampaign() {
                const component = this.model;
                const campaign = component.getTrait('campaign');
                let companyId = campaign.attributes.value.split('_')[0];
                let dealId = campaign.attributes.value.split('_')[1];
                _self.props.loadDealCampaigns(companyId, dealId);
            },
            changeRedirect() {
                const component = this.model;
                const properties = this.model.attributes.attributes;
                if (properties.redirect_checkbox) {
                    component.addTrait({
                        type: 'input',
                        name: 'redirect_to',
                        label: 'redirect to',
                    }, { at: 5 });
                } else {
                    component.removeTrait('redirect_to');
                }
            },
            changeTrait() {
                const component = this.model;
                const properties = component.attributes.attributes;

                if (properties.integration === true) {//when integration
                    component.removeTrait('method');
                    component.removeTrait('action');
                    component.removeTrait('redirect_to');

                    component.addTrait({//campaign
                        type: 'select',
                        name: 'campaign',
                        label: 'Select campaign',
                    }, { at: 1 });
                    component.addTrait({//integration
                        type: 'text',
                        name: 'method',
                        label: 'Method',
                        attributes: { style: 'display:none' }
                    }, { at: 2 });
                    component.addTrait({//integration
                        type: 'select',
                        name: 'action',
                        label: 'Select Integration',
                    }, { at: 3 });
                    component.addTrait({//redirect checkbox
                        type: 'checkbox',
                        name: 'redirect_checkbox',
                        label: 'redirect on submission',
                    }, { at: 4 });
                    if (properties.redirect_checkbox) {//when redirect
                        component.addTrait({
                            type: 'input',
                            name: 'redirect_to',
                            label: 'redirect to',
                        }, { at: 5 });
                    }
                } else {//common form method
                    component.removeTrait('method');
                    component.removeTrait('action');
                    component.removeTrait('campaign');
                    component.removeTrait('redirect_checkbox');
                    component.removeTrait('redirect_to');

                    component.addTrait({//method
                        type: 'select',
                        label: 'Method',
                        name: 'method',
                        options: [
                            { value: 'get', name: 'GET' },
                            { value: 'post', name: 'POST' },
                        ]
                    }, { at: 1 });
                    component.addTrait({//action
                        type: 'text',
                        id: 'action',
                        name: 'action',
                        label: 'Action',
                    }, { at: 2 });
                }
            },
            onRender() {
            }
        }
    });

    const undoManager = editor.UndoManager
    undoManager.start();

    editor.on('run:preview', () => {
        this.setState({
            ...this.state,
            zIndex: 1
        })
    });
    editor.on('stop:preview', () => {
        this.setState({
            ...this.state,
            zIndex: 4
        })
    });

    editor.on('component:selected', async (model) => {
        if (model.attributes.type === "form") {
            if (model.attributes.type === "form") {
                const component = editor.getSelected(); //Form component
                const properties = model.attributes.attributes;

                component.removeTrait('action');
                component.removeTrait('method');
                component.removeTrait('campaign');
                component.removeTrait('redirect_checkbox');
                component.removeTrait('redirect_to');

                if (properties.integration === true) {//when integration
                    component.addTrait({//campaign
                        type: 'select',
                        name: 'campaign',
                        label: 'Select campaign',
                    }, { at: 1 });
                    component.addTrait({//method
                        type: 'text',
                        name: 'method',
                        label: 'Method',
                        attributes: { style: 'display:none' }
                    }, { at: 2 });
                    component.addTrait({//integration
                        type: 'select',
                        name: 'action',
                        label: 'Select Integration',
                    }, { at: 3 });
                    component.addTrait({//redirect checkbox
                        type: 'checkbox',
                        name: 'redirect_checkbox',
                        label: 'redirect on submission',
                    }, { at: 4 });
                    if (properties.redirect_checkbox) {//when redirect
                        component.addTrait({
                            type: 'input',
                            name: 'redirect_to',
                            label: 'redirect to',
                        }, { at: 5 });
                    }
                } else {//common form method
                    component.addTrait({//method
                        type: 'select',
                        label: 'Method',
                        name: 'method',
                        options: [
                            { value: 'get', name: 'GET' },
                            { value: 'post', name: 'POST' },
                        ]
                    }, { at: 1 });
                    component.addTrait({//action
                        type: 'text',
                        id: 'action',
                        name: 'action',
                        label: 'Action',
                    }, { at: 2 });
                }

                if (properties.integration) {
                    _self.props.getCompanyDeals();
                    if (properties.campaign) {
                        let companyId = properties.campaign.split('_')[0];
                        let dealId = properties.campaign.split('_')[1];
                        _self.props.loadDealCampaigns(companyId, dealId);
                    }
                }
            }
        }
    });

    editor.on('storage:end:store', async(item) => {
        // this.setCountDownStyle(editor);
    });

    editor.load();
    editor.render();

    this.setState({
        ...this.state,
        editor: editor
    });

    setTimeout(() => {
        this.setCountDownStyle(editor);
    }, 1000);
}
componentDidUpdate(prevProps) {
    const { deals, campaigns } = this.props;
    const { editor } = this.state;

    if (this.props.deals !== prevProps.deals) {
        const campaignOptions = deals.map(deal => {
            return {
                value: deal.company.id + '_' + deal.id,
                name: deal.name
            }
        })
        const component = editor.getSelected();
        if (component.attributes.attributes.integration) {
            component.getTrait('campaign').set('options', campaignOptions);
        }
    }
    if (this.props.campaigns !== prevProps.campaigns) {
        const integrationOptions = campaigns.map(campaign => {
            return {
                value: `${config.get('REACT_APP_API_SERVER')}/v1/campaigns/${campaign.uuid}/leads`,
                name: campaign.name
            }
        })
        const component = editor.getSelected();
        if (component.attributes.attributes.integration) {
            component.getTrait('action').set('options', integrationOptions);
        }
    }
}

preview = (run) => {
    const { editor } = this.state;
    const commandManager = editor.Commands
    if (run === true) {
        commandManager.get('preview').run(editor)
        this.setState({ ...this.state, zIndex: 1 });
    } else {
        commandManager.get('preview').stop(editor)
        this.setState({ ...this.state, zIndex: 4 });
    }
}

undo = () => {
    const { editor } = this.state;
    const undoManager = editor.UndoManager
    if (undoManager.hasUndo()) {
        undoManager.undo();
    }
}

redo = () => {
    const { editor } = this.state;
    const undoManager = editor.UndoManager
    if (undoManager.hasRedo()) {
        undoManager.redo();
    }
}

changePage = (e, data) => {
    const { pages } = this.props;
    const { editor } = this.state;

    pages.map((page, pindex) => {
        if (page.id === data.value) {
            localStorage.setItem('gjsProject', page.gjs);
            if (!page.gjs) {
                localStorage.setItem("gjsProject", JSON.stringify(defaultPage))
            }
            editor.load();

            this.setState({
                ...this.state,
                selPage: data.value,
                pindex: pindex,
            })
        }
    });

}

save = async () => {
    const { editor, selPage } = this.state;
    const { pages } = this.props;
    let pageID = selPage === 0 ? pages[0].id : selPage;
    var _self = this.props;

    if (pages.length) {
        if (pages[0].id === selPage) {
            const iframe = document.querySelector('iframe.gjs-frame');
            htmlToImage.toJpeg(iframe.contentWindow.document.body).then(function (dataUrl) {
                _self.savePage(editor, pageID, dataUrl);
            }).catch(function (error) {
                _self.savePage(editor, pageID, '');
                console.error("oops, something wents wrong! but saved!", error);
            });
        } else {
            this.props.savePage(editor, pageID, '');
        }
    }
}

add = () => {
    this.props.showModal({ show: true, type: 0, id: 0 });
}

export = () => {
    const { editor } = this.state;
    editor.runCommand('gjs-export-zip');
}

delete = () => {
    const { selPage } = this.state;
    const { pages, sendMessage } = this.props;
    let pageID = selPage === 0 ? pages[0].id : selPage;

    if (selPage === 0 || selPage === pages[0].id) {
        sendMessage('Can\'t delete index page!', true);
        this.setState({
            ...this.state,
            show: false,
        })
    } else {
        this.props.deletePage(pageID);
        this.setState({
            ...this.state,
            show: false,
            selPage: pages[0].id
        })
    }
}

stateChange = (states) => {
    this.setState({
        ...this.state,
        ...states
    })
}

duplicate = () => {
    const { selPage, editor } = this.state;
    const { pages } = this.props;
    let pageID = selPage === 0 ? pages[0].id : selPage;
    this.props.showModal({ show: true, type: 1, editor: editor, id: pageID });
}

seo = () => {
    const { selPage, pindex } = this.state;
    const { pages } = this.props;
    let pageID = selPage === 0 ? pages[0].id : selPage;
    this.props.showModal({ show: true, type: 2, id: pageID, name: pages[pindex].name, pagetitle: pages[pindex].title, description: pages[pindex].description });
}

stateChange = (states) => {
    this.setState({
        ...this.state,
        ...states
    })
}

setCountDownStyle = (editor) => {
    editor.setStyle("");
    if (JSON.parse(localStorage.getItem("gjsProject"))){
        const gjsStyles = JSON.parse(localStorage.getItem("gjsProject")).styles;

        gjsStyles.map((item, index) => {
            editor.addStyle(item);

        });
    }
}

getStylePropertyName = (key) => {
    let str = '';
    if (key.indexOf("-")) {
        const keys = key.split("-");
        for (const i in keys) {
            str += keys[i].charAt(0).toUpperCase() + keys[i].slice(1);
        }
    }
    return str.charAt(0).toLowerCase() + str.slice(1);
}

render() {
    const { pages } = this.props;
    const { selPage, zIndex, show } = this.state;

    const pageOptions = pages.map((page, index) => ({
        key: index,
        text: page.name,
        value: page.id,
    }));

    return (
        <>
            <BuildModal />
            <Modal
                size={"mini"}
                open={show}
                onClose={() => this.stateChange({ show: false })}
            >
                <Modal.Header>Delete Page?</Modal.Header>
                <Modal.Content>
                    <p>Are you sure you want to delete your page?</p>
                </Modal.Content>
                <Modal.Actions>
                    <Button negative onClick={() => this.stateChange({ show: false })}>
                        No
                    </Button>
                    <Button positive onClick={() => this.delete()}>
                        Yes
                    </Button>
                </Modal.Actions>
            </Modal>
            <Button onClick={() => window.location.href='/pages'} color="grey" className="page_back" style={{ zIndex: zIndex }}><i className='ti ti-arrow-left' /></Button>
            <Button.Group className='control page' style={{ zIndex: zIndex }}>
                <Dropdown onChange={(e, data) => this.changePage(e, data)} value={selPage} selection options={pageOptions} className="page_list" />
                <Popup
                    trigger={<Button circular icon='ellipsis horizontal' className="page_setting" />}
                    content={
                        <Button.Group vertical className='page_actions'>
                            <Button onClick={() => this.stateChange({ show: true })}>Delete</Button>
                            <Button onClick={() => this.duplicate()}>Duplicate</Button>
                            <Button onClick={() => this.seo()}>SEO Settings</Button>
                        </Button.Group>
                    }
                    flowing hoverable
                    position='bottom center'
                />
                <Button onClick={() => this.add()} color="blue" className="page_add"><i className='ti ti-plus' /></Button>
                <Button onClick={() => this.export()} color="blue" className="page_export"><i className='ti ti-download' /></Button>

            </Button.Group>
            <Button.Group className='control demo' style={{ zIndex: zIndex }}>
                <Button onClick={() => this.preview(true)} className="page_preview">Preview</Button>
                <Button onClick={() => this.save()} color="blue" className="page_save">Save</Button>
            </Button.Group>
            <Icon onClick={() => this.preview(false)} style={{ zIndex: 5 - zIndex }} name="eye slash" size='big' className="page_preview"></Icon>
            <Button.Group className='control history' style={{ zIndex: zIndex }}>
                <Button onClick={() => this.undo()} icon="undo" className="page_undo"></Button>
                <Button onClick={() => this.redo()} icon="redo" className="page_redo"></Button>
            </Button.Group>

            <div id="gjs">
            </div>
            <Loader />
        </>
    );
}

}

export default compose(BuildContainer, BuildFormContainer, MessagesContainer, DealsContainer, CampaignsContainer)(Builder);

alexjoe118 commented 1 year ago

on my local image on deployed server side image

artf commented 1 year ago

This looks more an issue on your deploy side