0.0.4 • Published 26 days ago

@romanmazyrin/amocrm_widget_framework v0.0.4

Weekly downloads
-
License
MIT
Repository
-
Last release
26 days ago

Amocrm widget framework

Library to make amoCRM widgets development easier and faster. Includes often used components that are essential for widget core functionality.

Built with

webpack react esLint npm jest babel

Table of contents

Install

Installation by NPM package manager npm

npm install --save amocrm_widget_framework

You must include react in your project as well. Usually react is installed automatically as peer-dependency during npm install process. However, you must include React in your project explicitly, either in ES6 modules via import statement or in require function as a dependency or directly include react on a web page as third-party package.

Using

Destination main file of the lib is built in UMD format. That means you can use this lib with any module system you are used to work with. All the next documentation examples are shown for ES6 modules.

import {
    createWidget,
    SettingsButtonsComponent,
    SettingsContactFormComponent,
    SettingsPhoneFieldComponent,
    SubscriptionManagerComponent,
    VideoInstructionComponent,
    SettingsSaverComponent,
    SettingsFooterComponent,
} from 'amocrm_widget_framework';

But you can import this lib via AMD (define/require), CommonJS (require) and even include destination script direct on a web page and use components via global variable amocrm_widget_lib).

How the library works

There is a core function inside the lib createWidget(config). That function creates and returns another constructor-function founded on the passed configuration. Result constructor-function has to be imported in script.js file.

Widget configuration includes:

  1. Widget components (components)
  2. Widget lifecycle events handlers (events)

During the widget initialization inside amoCRM (i. e. widget instance is being creating) some things happen:

  1. Instances of components from the configuration is being creating. Those instances subscribes on widget events after that.
  2. Events handlers from configuration subscribes on widget events as well.
  3. All neccessary callbacks is being creating in the widget instance attribute 'callbacks'. The only thing happens inside those callbacks is to call the exact event corresponpding to that callback and pass the event name and widget instance inside that event.

Configuration example

const config = {
    components: {
        videoInstruction: {
            class: VideoInstructionComponent,
        },
        settingsContactForm: {
            class: SettingsContactFormComponent,
            params: {
                text: '{{lang.components.settings_contact_form.text}}',
                contactButtons: [
                    {
                        type: 'telegram',
                        params: {
                            text: '{{lang.components.settings_contact_form.buttons.telegram.text}}',
                            username: '{{lang.components.settings_contact_form.buttons.telegram.username}}',
                        },
                    },
                    {
                        type: 'whatsapp',
                        params: {
                            text: '{{lang.components.settings_contact_form.buttons.whatsapp.text}}',
                            phone: '{{lang.components.settings_contact_form.buttons.whatsapp.phone}}',
                        },
                    },
                    {
                        type: 'email',
                        params: {
                            text: '{{lang.components.settings_contact_form.buttons.email.text}}',
                            email: '{{lang.components.settings_contact_form.buttons.email.email}}',
                        },
                    },
                    {
                        type: 'link',
                        params: {
                            text: '{{lang.components.settings_contact_form.buttons.site.text}}',
                            href: '{{lang.components.settings_contact_form.buttons.site.link}}',
                        },
                    },
                ],
                callbackForm: {
                    successText: '{{lang.components.settings_contact_form.callback_form.success_text}}',
                    failText: '{{lang.components.settings_contact_form.callback_form.fail_text}}',
                    sendButtonText: '{{lang.components.settings_contact_form.callback_form.send_button_text}}',
                    phoneFieldPlaceholder: '{{lang.components.settings_contact_form.callback_form.phone_field_placeholder}}',
                    url: 'https://webhook.site/eb5e4c54-99a4-4ced-a5af-b87084b6fdaf',
                },
            },
        },
        settingsButtons: {
            class: SettingsButtonsComponent,
            params: {
                buttons: [
                    {
                        type: 'link',
                        params: {
                            text: '{{lang.components.settings_buttons.auth_btn}}',
                            href: 'https://mazdata.ru/all-client-leads-integration/oauth?amo_subdomain={{system.domain}}',
                            style: {
                                backgroundColor: 'green',
                                color: 'white',
                                width: '350px',
                            },
                            classname: 'button-input',
                        },
                    },
                ],
            },
        },
        subscriptionManager: {
            class: SubscriptionManagerComponent,
            params: {
                statusUrl: 'https://mazdata.ru/google-drive-integration/get-integration-status',
            },
        },
        settingsPhoneField: {
            class: SettingsPhoneFieldComponent,
            params: {
                phoneFieldOpts: {
                    initialCountry: 'RU',
                    preferredCountries: ['RU', 'UA', 'BY', 'KZ'],
                },
            },
        },

        settingsSaver: {
            class: SettingsSaverComponent,
            params: {
                url: 'https://webhook.site/eb5e4c54-99a4-4ced-a5af-b87084b6fdaf',
            },
        },

        settingsFooter: {
            class: SettingsFooterComponent,
            params: {
                siteDomain: 'deltasales.ru',
                fromYear: '2013',
                email: "info@deltasales.ru",
                text: '{{lang.components.settings_footer.text}}'
            }
        }
    },

    events: {
        [WidgetLifecycleEvents.EVENT_INIT]: (eventName, widget) => {
            // do something on INIT event;
        }
    }
};

Components

What is a component?

By "component" inside this lib we mean some instance that initializes once during the widget creation, subscribes on widget events and handles events triggers after that. Components instances are available by calling widget method component(componentName).

const sm = widget.component('subscriptionManager');
const status = await sm.getStatus();

During the component creation (which happens in the middle of widget instance creating process) two arguments are passed in the component constructor. The first - instance of the widget itself. The second - set of parametees from configuration under the params key.

In one word, component is a thing which:

  1. Has to be instantiated only once.
  2. Has to be available globally within widget.
  3. Can (but not must) subscribe on widget events and execute handlers on those events.

Component's configuration

Component's configuration consists of 3 main parts:

  1. Components's key in configuration. That key is neccessary for further component getting from the widget by widget.component('keyFromConfiguration') method.
  2. Parameter class. This parameter accepts class that is inherited from WidgetComponent class.
  3. Parameter params. This parameter is an object which is passed to the component's constructor in the exact same structure it is presented in configuration.

Component configuration example:

settingsFooter: {
    class: SettingsFooterComponent,
    params: {
        siteDomain: 'deltasales.ru',
        fromYear: '2013',
        email: "info@deltasales.ru",
        text: '{{lang.components.settings_footer.text}}'
    }
}

The instance of class SettingsFooterComponent will be created on widget initialization. While instance is being creating it accepts widget instance and an object under the key params. In further you can retrieve component instance by calling widget.component('settingsFooter').

Built-in library components

  • VideoInstruction
  • SettingsContactForm
  • SettingsButtons
  • SubscriptionManager
  • SettingsPhoneField
  • SettingsSaver
  • SettingsSaver
  • SettingsFooter

Detailed instructions of each component are available on links.

Custom component creating

  1. Create component class. Inherit it from WidgetComponent
  2. Override the method getWidgetEventsCallbacks().
import WidgetLifecycleEvents from 'amocrm_widget_framework';
import WidgetComponent from 'amocrm_widget_framework';

class MyOwnComponent extends WidgetComponent {
    constructor(widget, params) {
        super(widget);
        //this.params = params; etc...;
    }

    getWidgetEventsCallbacks() {
        return {
            [WidgetLifecycleEvents.EVENT_SETTINGS]: this.settings.bind(this),
        };
    }

    settings(eventName, widget) {
        // Do something when settings event will be triggered;
    }
}
  1. For further using you have to add your new component in the configuration of createWidget method;
const config = {
    components: {
        //...
        myOwnComponentName: {
            class: MyOwnComponent,
            params: {
                someParamName: 'Hi there!'
            }
        },
        //...
    }
};

Widget events

AmoCRM widgets are working on callbacks runnig system. You can deep dive into that in the major documentation on the official amoCRM site(https://www.amocrm.ru/developers/content/integrations/script_js).

But we want different components (which often are not related with each other) to listen same events. For that purposes the "Events" mechanism was developed. When particular callback is called the widget just emit the "event" and those listeners which are subscribed on that event run their functional.

There is an object events to subscribe on the particular widget events in the configuration.

Keys of that object are events names, and values are callbacks for those events.

Important! Components handle events first, and only then events.

There are two ways to subscribe on events:

  1. Create custom component with callbacks on particular events, pass component to configuration.
  2. Create callbacks in the events object;

Widget events list

  • EVENT_RENDER - Emited on render() callback
  • EVENT_INIT - Emited on init() callback
  • EVENT_SETTINGS - Emited on settings() callback
  • EVENT_DP - Emited on dpSettings() callback
  • EVENT_TAB - Emited on loadPreloadedData() callback
  • EVENT_SAVE - Emited on onSave() callback

All this events exists as constants in the object WidgetLifecycleEvents

Event handler arguments

When handler handle event it accepts two arguments:

  1. Event name (from the list above)
  2. Widget instance.