@zohodesk/platform-middleware
Version:
Generalized Contract for the events from Marketplace App, In-App widgets, CRM-Plus and EFC
328 lines (289 loc) • 12 kB
JavaScript
import selectn from 'selectn';
function clearNonRuntimeWidgetInstances() {
var allwidgetsInstance = ZApp.GetAllWidgetInstance();
allwidgetsInstance = Object.keys(allwidgetsInstance);
var widgetInstance = null;
for (var i = 0; i < allwidgetsInstance.length; i++) {
widgetInstance = ZApp.GetWidgetInstance(allwidgetsInstance[i]);
if (widgetInstance.getIFrame() === null) {
ZApp.DeleteWidgetInstance(allwidgetsInstance[i])
}
}
}
function patchString(string, data) {
if (!string || typeof string !== 'string') {
throw new Error('Invalid String');
}
if (!data || typeof data !== 'object') {
throw new Error('Invalid Params object');
}
let patchedString = string.replace(/\{\{\w+\}\}?/g, match => {
let key = match.replace(/[{{}}]/g, '');
return data[key] || match;
});
return patchedString;
}
function isObject(obj) {
return obj.constructor === {}.constructor;
}
// function getComputedParams(paramsObj) {
// return Object.keys(paramsObj.computeParams).reduce((result, param) => {
// result[param] = selectn(patchString(paramsObj.computeParams[param], paramsObj.data), paramsObj.data);
// return result;
// }, {});
// }
// function paraseData(dataObj) {
// return Object.keys(dataObj.params).reduce((result, param) => {
// if (typeof dataObj.params[param] === "object") {
// paraseData({
// params: params[param],
// data: dataObj.data
// })
// } else {
// result[param] = selectn(patchString(dataObj.params[param], dataObj.data), dataObj.data);
// }
// return result;
// }, {});
// }
// export function constructDataForEvent(dataObj) {
// let computedParams = getComputedParams({ computeParams: dataObj.computeParams, data: dataObj.data });
// computedParams = Object.assign({}, computedParams, dataObj.data);
// return paraseData({ params: dataObj.params, data: computedParams });
// }
// export let zAppBroadcastEvent = (eventObj) => {
// if (typeof ZApp !== 'undefined') {
// clearNonRuntimeWidgetInstances();
// ZApp.BroadcastEvent(eventObj.name, eventObj.data);
// }
// PlatformInstance.BroadcastEvent({ name: eventObj.name, data: eventObj.data })
// }
function isValidEventObj(eventObj) {
return eventObj.eventName &&
eventObj.responseHandler &&
typeof eventObj.responseHandler == 'function' ? true : false
}
function hasWidgetsForEvent(eventName) {
return ZApp.GetWidgetsByEvent(eventName).length > 0 ? true : false;
}
export function isEventNeededToBroadCast(eventObj) {
return isValidEventObj(eventObj);
}
export let zAppBroadcastEvent = (eventObj) => {
let { getState, dispatch, action, event, getPrevState } = eventObj;
let { responseHandler, eventName } = event;
if (typeof eventName == 'function') {
eventName = eventName({ action, getState, getPrevState });
}
if (Array.isArray(eventName)) {
eventName.map((name) => {
responseHandler(action, getState, dispatch, name, getPrevState).then(function (response) {
if (typeof ZApp !== 'undefined') {
clearNonRuntimeWidgetInstances();
isObject(response) ? ZApp.BroadcastEvent(name, response) : null;
}
isObject(response) && typeof PlatformInstance != 'undefined' ? PlatformInstance.BroadcastEvent({ name, data: response }) : null;
});
})
} else {
responseHandler(action, getState, dispatch, eventName, getPrevState).then(function (response) {
if (typeof ZApp !== 'undefined') {
clearNonRuntimeWidgetInstances();
isObject(response) ? ZApp.BroadcastEvent(eventName, response) : null;
}
isObject(response) && typeof PlatformInstance != 'undefined' ? PlatformInstance.BroadcastEvent({ name: eventName, data: response }) : null;
});
}
}
export let zAppHookEvent = (eventObj) => {
return new Promise((resolve, reject) => {
let { getState, dispatch, action, hook } = eventObj;
let { responseHandler, eventName } = hook;
if (typeof eventName === 'function') {
eventName = eventName({ action, getState });
}
responseHandler(action, getState, dispatch, eventName).then(hookData => {
if (typeof ZApp !== 'undefined') {
clearNonRuntimeWidgetInstances();
let isTimeOutCalled = false, failedWidgets = [], eventListeners = ZApp.GetWidgetsByEvent(eventName);
if (eventListeners.length > 0) {
//TODO: Get the Hook Timing from the application
let eventTimeout = setTimeout(() => {
isTimeOutCalled = true;
resolve(eventObj.action);
}, 30000);
//Third argument true is set because of Hook Event
Promise.all(ZApp.BroadcastEvent(eventName, hookData, true)).then(response => {
let content = null;
if (!isTimeOutCalled) {
clearTimeout(eventTimeout);
response.map(widgetsResponse => {
let widgetInstance = ZApp.GetWidgetInstance(widgetsResponse.widgetID);
let widgetName = widgetInstance.getProp('title') || widgetInstance.getProp('name');
let responseObj = widgetsResponse.response && widgetsResponse.response[0] || {};
if (!responseObj.isSuccess) {
let widgetResult = responseObj.response || {};
let rejectTitle = widgetResult.title || '';
let shouldNotify = widgetResult.hasOwnProperty('shouldNotify') ? widgetResult.shouldNotify : true;
if(shouldNotify){
let rejectMessage = widgetResult.msg || widgetResult.message || '';
if (rejectMessage && typeof rejectMessage === 'string') {
content = rejectMessage.trim();
} else {
content = `This widget has stopped the ${eventName} operation`;
}
}
failedWidgets.push({
title: rejectTitle || widgetName,
content: content
});
} else {
widgetsResponse.response[0].response == false
? failedWidgets.push({
title: widgetName,
content: `This widget has stopped the ${eventName} operation`
})
: null;
}
});
if (failedWidgets.length) {
failedWidgets.forEach(widget => {
if(widget.content){
eventObj.notifyHandler({
title: widget.title,
content: widget.content
});
}
let hookRejectCallback = action.hookRejectCallback;
if (hookRejectCallback && typeof hookRejectCallback === 'function') {
hookRejectCallback();
}
});
} else {
resolve(eventObj.action)
}
}
}).catch(err => {
if (!isTimeOutCalled) {
clearTimeout(eventTimeout);
eventObj.notifyHandler({
title: 'Hook Event Failed',
content: `Some widget has stopped the ${eventName} hook event`
});
let hookRejectCallback = action.hookRejectCallback;
if (hookRejectCallback && typeof hookRejectCallback === 'function') {
hookRejectCallback();
}
}
})
} else {
resolve(eventObj.action)
}
}
}).catch(err => {
let hookRejectCallback = action.hookRejectCallback;
if (hookRejectCallback && typeof hookRejectCallback === 'function') {
hookRejectCallback(err);
}
reject(err);
});
});
}
function constructEventAndResponseObject(eventObj) {
var info = {};
if (eventObj.event.EVENT_FROM == 'PRODUCT') {
info = {
type: eventObj.event.type,
value: eventObj.event.payload,
property: eventObj.event.property
}
} else {
info = {
type: eventObj.event.data.type,
value: eventObj.event.data.value,
property: eventObj.event.data.property || null,
iframe: eventObj.event.iframe
}
}
function sendResponse(eventPromise, eventResponseObj) {
let data = eventResponseObj.data;
if (eventResponseObj.hasOwnProperty('status')) {
eventResponseObj.status ? eventPromise.resolve(data) : eventPromise.reject({ errMsg: data });
}
}
return {
info: info,
sendResponse: sendResponse.bind(null, eventObj.event.promise)
}
}
function constructWidgetObject(widgetId, extension_id) {
let widgetInstance = ZApp.GetWidgetInstance(widgetId);
return {
id: widgetInstance.getProp('widgetId'),
clientId: widgetId,
title: widgetInstance.getProp('title') || widgetInstance.getProp('name'),
extensionId: extension_id,
location: widgetInstance.getLocation()
};
}
export function handleEvent(eventObj) {
let { widgetID, extension_id } = eventObj.event;
let constructedEventObject = {
store: {
getState: eventObj.getState,
dispatch: eventObj.dispatch
},
patchString
};
if (widgetID && extension_id) {
constructedEventObject.widget = constructWidgetObject(widgetID, extension_id);
}
constructedEventObject.event = constructEventAndResponseObject(eventObj);
return constructedEventObject;
}
export function validateConfig(config) {
let errorMsg = null;
if (config.featureFlags.isMarketplaceNeeded) {
if (!config.hasOwnProperty('marketplace')) {
errorMsg = 'marketplace object is missing';
} else {
if (!(config.marketplace.hasOwnProperty('renderHandler') && typeof config.marketplace.renderHandler === 'function')) {
errorMsg = 'marketplace object should have renderHandler key with function as value'
}
if (!(config.marketplace.hasOwnProperty('postAssestsFetch') && typeof config.marketplace.postAssestsFetch === 'function')) {
errorMsg = 'marketplace object should have postAssestsFetch key with function as value'
}
if (!(config.marketplace.hasOwnProperty('isDevMode') && typeof config.marketplace.isDevMode === 'function')) {
errorMsg = 'marketplace object should have isDevMode key with function as value'
}
if (!(config.marketplace.hasOwnProperty('requestHandler') && typeof config.marketplace.requestHandler === 'function')) {
errorMsg = 'marketplace object should have requestHandler key with function as value'
}
if (!(config.marketplace.hasOwnProperty('notifyHandler') && typeof config.marketplace.notifyHandler === 'function')) {
errorMsg = 'marketplace object should have notifyHandler key with function as value'
}
}
}
if (!(config.hasOwnProperty('globalNameSpace') && typeof config.globalNameSpace === 'string')) {
errorMsg = 'globalNameSpace key with string as value is missing'
}
if (!(config.hasOwnProperty('postProductSDKAssetsFetch') && typeof config.postProductSDKAssetsFetch === 'function')) {
errorMsg = 'postProductSDKAssetsFetch key with function as value is missing'
}
if (!(config.hasOwnProperty('isPromiseBasedAction') && typeof config.isPromiseBasedAction === 'boolean')) {
errorMsg = 'isPromiseBasedAction key with true/false as value is missing'
}
if (!(config.hasOwnProperty('locale') && typeof config.locale === 'string')) {
errorMsg = 'locale key with string as value is missing'
}
if (!config.hasOwnProperty('eventListeners')) {
errorMsg = 'eventListeners object is missing';
} else {
Object.keys(config.eventListeners).forEach(key => {
if (!(typeof config.eventListeners[key] === 'function')) {
errorMsg = 'every keys in eventListeners object should have function as value'
return
}
});
}
return { isConfigValid: errorMsg ? false : true, errorMsg };
}