@romanmazyrin/amo_widget_components
v1.8.3
Published
Amocrm widgets components lib
Downloads
6
Readme
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] (#creating-components).
App lifecycle
On the start App is an empty container. It does not contains anything;
Then we start to fill App with components classes that must be inited. We do it by calling method addComponent();
Now we have list of classes inside App. Each class is a component.
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;
Then, we call init method on App. Init method accepts configuration object;
App.init({ 'param': 'value' });
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:
{ "ApiClient" : new ApiClient(config), "Users" : new Users(config), ... }
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:
showToastMessage(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:
Create component class extended from Component class;
export default class MyAwesomeComponent extends Component { ... }
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']; } }
Add the rest methods that you need in your component.
Add your component to App by App.addComponent(componentClass).
import App from './App'; import MyAwesomeComponent from "./AppComponents/MyAwesomeComponent"; App.addComponent(MyAwesomeComponent); export default App;
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:
- create action instance;
- 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 methodmessage
. 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;