1.8.3 • Published 1 year ago

@romanmazyrin/amo_widget_components v1.8.3

Weekly downloads
49
License
ISC
Repository
github
Last release
1 year ago

Publish NPM package npm

amo_widget_components

Common components for amocrm widgets

Contents

Installing

npm install @romanmazyrin/amo_widget_components -D

Using

This package exports some Javascript classes and some riot components, and it use ES6 export command;

So, when you import this package in project, you must declare what exactly you want to import;

import {App, WidgetDescription} from '@romanmazyrin/amo_widget_components';

List of package exported classes you could find below

Main components

App

App is something like global container for widget instance. App contains global configuration and map of inited components. You must call static init method of App only once and pass configuration object inside it.

App.init(
    "baseUrl" : "https://google.com",
    "widget_name": "hello-widget"
});

Inited app has method for getting inited components.

let someComponent = App.component("someComponentName");
someComponent.someMethod(1, 2, 3);

// or

App.component("someComponentName").someMethod(1, 2, 3);

WidgetDescription

WidgetDescription is riot shell object that used for creating description in widget settings. It consists of another nested riot components and must be configured with props.

var CustomWidget = function() {

    this.callbacks = {

        settings: function() {

            var descriptionBlock = document.querySelector(".widget_settings_block__descr");
            descriptionBlock.innerHTML = "";

            let descriptionComponent = riot.component(Components.WidgetDescription);
            let description = descriptionComponent(descriptionBlock, {
                "videoInstructionSrc" : "https://www.youtube.com/embed/y_GM7L4sHME",
                'description' : "<div class=\"description-text\">\n" +
                    "        <p>\n" +
                    "            Выставляйте счета на онлайн-оплату от Robokassa вручную из карточки сделки или автоматически на любом этапе воронки!<br>\n" +
                    "            <br>\n" +
                    "            Виджет позволяет:<br>\n" +
                    "            - выставлять счета из карточки сделки <br>\n" +
                    "            - выставлять счета автоматически через digital-воронку<br>\n" +
                    "            - передавать ссылку на оплату в поле сделки (чтобы оттуда ее можно было автоматически отправить)<br>\n" +
                    "            - указывать срок действия ссылки на оплату и назначение платежа<br>\n" +
                    "            - получать email-уведомления о клиентских оплатах на общую почту и на почту ответственного менеджера<br>\n" +
                    "        </p>\n" +
                    "    </div>",
                'actionButtons' : [
                    {
                        'type': 'link',
                        'text': 'Авторизация виджета',
                        'href': self.app._config['apiBaseUrl'] + "/oauth",
                        'btnClassname': 'robokassa-link-btn'
                    },
                    {
                        'type': 'primary',
                        'text': "Открыть настройки",
                        'showOnlyIfInstalled': true,
                        'btnClassname': 'button-input_blue',
                        'onClick' : function(e) {
                            self.app.component("Modal").openModal("<settings-panel></settings-panel>", {});
                            riot.component(Components.SettingsPanel)(document.querySelector("settings-panel"), {});
                        }
                    }
                ],
            
                'helpOrderFields': {
                    "email" : self.getAmoLogin()
                }
            });
        }
    }
};

Here is a list of props, that used for configuring WidgetDescription:

  • videoInstructionSrc - link to youtube video instruction. If not setted - video instruction block will not be shown;
  • description - html block with description.
  • actionButtons - array of objects. Each object is button configuration. It is 2 types of buttons at the moment: link and primary. Button configuration object has next params:

    Common:

    • type - can be 'link' or 'primary';
    • text - text on button';
    • showOnlyIfInstalled - button is shown only if WidgetDescripton state "isInstalled" is true;
    • btnClassname - class for button
    • btnStyle - style attribute value for button
    • containerClassname - class for button container html tag
    • containerStyle - style attribute value for button container

      Link button:

    • href - href attribute value for link button

      Primary button:

    • onClick - onclick callback for button

  • helpOrderFields - additional data for sending to server with helpOrder request

Component

Base class that every App component extends. Instruction for creating custom App components you could see here.

App lifecycle

  1. On the start App is an empty container. It does not contains anything;
  2. Then we start to fill App with components classes that must be inited. We do it by calling method addComponent();
  3. Now we have list of classes inside App. Each class is a component.
  4. We also can add some attributes directly to App. It is used for adding some global stuff that is not components;

     import Clipboard from "clipboard/dist/clipboard";
     App.Clipboard = Clipboard;
  5. Then, we call init method on App. Init method accepts configuration object;

    App.init({
        'param': 'value'
    });
  6. When we run init method, App takes every class from prepared components list, and build map where key - if component class name, and value - component instance. Something like this:

    ```javascript
    {
       "ApiClient" : new ApiClient(config),
       "Users" : new Users(config),
       ...
    }
    ```
  7. Then App save this map inside, and we can get any component by calling App.component('componentName');

App components

Before App inited, it contains list of components that must be inited, inside container. Default App, that imported from package, already contains some default components inside. But you can add your custom components by calling static method App.addComponent(class), where class is imported custom component class. Example below:

import {App, WidgetDescription} from '@romanmazyrin/amo_widget_components';
import SettingsPanel from "./tags_source/settings-panel/settings-panel.riot";
import SomeUsefulComponent from "./AppComponents/SomeUsefulComponent";

App.addComponent(SomeUsefulComponent);

export {
    App,
    WidgetDescription,
    SettingsPanel
};

And now, we have SomeUsefulComponent added to list of components, that must be inited while App initialize;

Adding component with alias

You can also add components with alias name, by adding second param in addComponent(componentClass, aliasName) method.

App.addComponent(SomeUsefulComponent, 'coolStuff');

// and then getting this component

App.component("coolStuff").makeSomeStuff();

Here is a list of default App components included in package:

  • ApiClient
  • SubscriptionStatusManager
  • Utils
  • StyleLoader
  • Toastr
  • Modal
  • Pipelines
  • Preloader
  • CustomFields
  • EntitiesTemplateTags
  • RightPanelManager

SubscriptionStatusManager methods:

fetchIntegrationStatus():

Make NEW REQUEST to server with Promise, save this promise inside and returns it.

getIntegrationStatus():

Returns existed Promise of fetching integration status, or do fetchIntegrationStatus() firstly and then return saved promise.

getInstalledStatus():

Returns Promise with true or false in result. True - widget installed. False - not installed;

getSubscriptionStatus():

Returns Promise with SubscriptionStatus in result param. SubscriptionStatus has next methods: getIsExpires(), getStatusText().

getIsExpired(): returns true or false.

getStatusText(): returns string with widget expiring status: "Виджет приобретен", "Срок действия виджета до 01.01.2021" etc.

Here is example of using:

App.component('SubscriptionStatusManager').getSubscriptionStatus()
.then((status) => {
    if (status.getIsExpired()) {
        alert("Виджет истек. Оплатите!");
    }
})

getFilledDataStatus():

Returns Promise with true or false. True - means user filled contact data, it is okay. False - data has not been filled.

ApiClient description:

configuration params:

  • apiBaseUrl - base url for api requests. MUST NOT contain slash at the end.;
  • amoSubdomain - amocrm current account subdomain;

Methods:

getBaseApiUrl():

Returns apiBaseUrl param passed during initialization;

api(action, type, data):

Makes api request to server. Params description below:

  • action - server api action. MUST NOT CONTAIN slash at the beginning;
  • type - request method. GET or POST;
  • data - data for sending to server. It is object with keys (param name) and values (param value). This object already contains param "amo_subdomain" in every request;

Returns Promise with server response in result;

Here is example of using:

App.component("ApiClient").api("save-settings", "POST", {
    "setting_1" : "setting_1_value",
    "setting_2" : "setting_2_value"
})
.then(function(response) {
    console.log(response);
});

CustomFields description:

Methods:

fetchCustomFields():

Make NEW REQUEST to server with Promise, save this promise inside and returns it.

getCustomFields():

Returns existed Promise of fetching customFields, or do fetchCustomFields() firstly and then return saved promise. Value of Promise is array of customFields;

getEntityCustomFieldsForSelectByEntityType(entityType):

Returns Promise with customFields of entityType or null;

getEntityCustomFieldsFormatted(entityType, mapParams):

Returns Promise of customField using entityType and mapParams or null object. mapParams - object of type

{
key : value,
...
}

where key is the new name of the field, value is the old name of the field (taken from the customField array by entityType key).

EntitiesTemplateTags description:

Methods:

fetchEntitiesTemplateTags():

Make NEW REQUEST to server with Promise, save this promise inside and returns it.

getEntitiesTemplateTags():

Returns existed Promise of fetching customFields, or do fetchCustomFields() firstly and then return saved promise. Value of Promise is array of customFields;

Modal description:

configuration params:

  • modal - Modal class from amocrm library;
  • widgetSysName - system name of widget. It is used in modal window classname. This classname builds like this: this._widgetName + '-modal-window';

Methods:

openModal(html, options):

  • html - html code that will be placed in modal window;
  • options - options for modal window class. You can find documentation for Modal class here

Returns modal class instance;

Pipelines description:

Methods:

fetchPipelines():

Make NEW REQUEST to server with Promise, save this promise inside and returns it.

getPipelines():

Returns existed Promise of fetching pipelines status, or do fetchPipelines() firstly and then return saved promise. Value of Promise is array of pipelines;

getPipelineById(pipelineId):

Returns Promise with value of pipeline object or null;

StyleLoader description:

Methods:

loadStyle(src, onload):

Load style on page by adding \<style> tag in head;

  • src - link to style
  • onload - callback which runs when style fully loaded;

Toastr description:

configuration params:

  • widgetI18nName - widget human-readable name. Used in toast header;

Methods:

bashowToastMessage(type, text):

  • type - type of toast (success, error etc.). You can see all types here
  • text - text to be shown

Utils description:

Methods:

isOneConditionTrue(arrayOfConditions):

Returns true if there is at least one True in array. Example:

if (App.components("Utils").isOneConditionTrue([
    3 === 4, // false
    false, // false
    "Hello".length === 5 // true
])) {
    // This code will run
} else {
    // This code will NOT run
}

isAllConditionsTrue(arrayOfConditions):

Returns true if all elements of array are True. Example:

if (App.components("Utils").isOneConditionTrue([
    3 === 3, // true
    true, // true
    "Hello".length === 5 // true
])) {
    // This code will run
} else {
    // This code will NOT run
}

Preloader description (from 1.2.0):

configuration params:

  • riot - riot lib;
  • preloaderImageSrc - src path to loader image;

Methods:

turnOn():

show preloader

turnOff():

hide prealoder

setImageSrc(src):

update preloader image src

RightPanelManager description (from 1.5.0):

configuration params:

  • riot - riot lib;
  • widgetSysName - system name of widget;
  • widget - widget object which implements method render_template(...);

Methods:

renderRiotTagOnRightPanel(riotComponentShell, props):

Render and mount riot tag in the right panel in current entity card.

Creating components:

You must do steps described below to create and add your custom component in App:

  1. Create component class extended from Component class;

    export default class MyAwesomeComponent extends Component { ... }
  2. Define constructor method with one param (config). Call super() method inside constructor.

    "Config" is an object which we pass to App.init() method. Every component accept this object in their constructor method. Thus inside every component constructor we have access to full App configuration. And in constructor method we must save that params that component need for working. Example:

    export default class MyAwesomeComponent extends Component {
        constructor(config) {
            super();
            
            // Save that params that we need;
            this._apiBaseUrl = config['apiBaseUrl'];
            this._amoSubdomain = config['amoSubdomain'];
        }
    }
  3. Add the rest methods that you need in your component.

  4. Add your component to App by App.addComponent(componentClass).

    import App from './App';
    
    import MyAwesomeComponent from "./AppComponents/MyAwesomeComponent";
    
    App.addComponent(MyAwesomeComponent);
    
    export default App;
  5. Now you can use your component like this:

    App.component("MyAwesomeComponent").someMethod();

Widget actions

There are a lot of code from one widget to another, which can be reused (checking widget status before running, mounting settings description etc.). So in this package you can find Actions classes, where such kind of code is situated. Every Action is exported from index.js in BaseActions namespace.

What is action?

Action is a class, which can accept some arguments in constructor, and implements method run(params).

How to call action?

Action called in 2 steps:

  1. create action instance;
  2. call method run;

Calling action example

this.callbacks = {

    render: function() {
        (new Components.BaseActions.CheckSubscriptionStatusAndRunCallbackAction(self.app.component('SubscriptionStatusManager')))
            .run(self.start);
        return true;
    },
    init: function() {
        (new Components.BaseActions.LoadStylesAction(self.app.component("StyleLoader"))).run(self.getStylesList());

        (new Components.BaseActions.CheckSubscriptionStatusAndShowMessageAction(
            self.app.component("SubscriptionStatusManager"), {
                "message": function(msg) {
                    self.app.component("Toastr").showToastMessage("error", msg);
                }
            }
        )).run();

        return true;
    }
};

Actions list

CheckSubscriptionStatusAndRunCallbackAction:

  • constructor(subscriptionStatusManager) params:

    • subscriptionStatusManager - instance of src/AppComponents/SubscriptionStatusManager/SubscriptionStatusManager;
  • run(callback) params:

    • callback - callback function without arguments. This function will be runned if widget NOT EXPIRED, INSTALLED and DATA FILLED;

CheckSubscriptionStatusAndShowMessageAction:

  • constructor(subscriptionStatusManager, messageProcessor) params:

    • subscriptionStatusManager - instance of src/AppComponents/SubscriptionStatusManager/SubscriptionStatusManager;
    • messageProcessor - object with method message. This method accepts 1 param - text to show;

LoadStylesAction:

  • constructor(styleLoader) params:

    • styleLoader - instance of src/AppComponents/StyleLoader;
  • run(stylesList) params:

    • stylesList - array of paths to styles;

MountDescriptionAction:

Call this action only in settings callback!

  • constructor(riot, descriptionShellObj) params:

    • riot - riot lib;
    • descriptionShellObj - riotShellObject which will be mounted to description panel;
  • run() params:

    • descriptionProps - props for descriptionShellObj (description component);

BindSettingsHandlersAction:

Call this action only in settings callback!

  • constructor(PhoneField, subscriptionStatusManager, apiClient) params:

    • PhoneField - PhoneField lib class;
    • subscriptionStatusManager - instance of src/AppComponents/SubscriptionStatusManager/SubscriptionStatusManager;
    • apiClient - instance of src/AppComponents/ApiClient;
  • run(descriptionRiotObj, extraData, phoneFieldOpts) params:

    • descriptionRiotObj - description riot mounted component;
    • extraData - extra data for sending to server to save-settings;
    • phoneFieldOpts - opts for PhoneField lib;

1.8.3

1 year ago

1.8.2

2 years ago

1.8.1

3 years ago

1.8.0

3 years ago

1.7.0

3 years ago

1.6.0

3 years ago

1.5.0

3 years ago

1.4.5

3 years ago

1.4.4

3 years ago

1.4.3

3 years ago

1.4.2

4 years ago

1.4.1

4 years ago

1.4.0

4 years ago

1.3.0

4 years ago

1.2.0

4 years ago

1.1.5

4 years ago

1.1.4

4 years ago

1.1.3

4 years ago

1.1.2

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.3

4 years ago

1.0.0

4 years ago