equal-angular-pfm-sdk
Version:
Equal PFM Angular SDK
228 lines (207 loc) • 8.7 kB
JavaScript
/**
* @typedef {Object} SDKCallbackData
* @property {string} eventType - Type of event ('PFM_SDK_CALLBACK', 'EQUAL_SDK_CALLBACK', etc.)
* @property {string} status - Status of the event ('ON_CLOSE', 'ERROR', etc.)
* @property {string} [statusCode] - Status code for error events
* @property {string} message - Message associated with the event
* @property {string} [transaction_id] - Optional transaction ID
* @property {string} [url] - Optional URL for navigation events
*/
/**
* @typedef {function(SDKCallbackData): void} SDKCallback - Callback function for SDK events
*/
var equalCloseEvent;
var equalErrorEvent;
var win;
var clientViewPort;
var intervalID;
const _PFM_APP_URL = {
"prod": "https://pfm.equal.in",
"uat": "https://uat.pfm.equal.in",
}
/**
* Checks if the device is running iOS
* @returns {boolean} True if the device is running iOS, false otherwise
* @private
*/
const _isIOSMobile = () => {
if (navigator.userAgent.match(/iPhone/i)
|| navigator.userAgent.match(/iPad/i)
|| navigator.userAgent.match(/iPod/i)) {
return true;
} else {
return false;
}
};
/**
* Checks if the device is a mobile device
* @returns {boolean} True if the device is mobile, false otherwise
* @private
*/
const _isMobileDevice = () => {
if (navigator.userAgent.match(/Android/i)
|| navigator.userAgent.match(/webOS/i)
|| navigator.userAgent.match(/iPhone/i)
|| navigator.userAgent.match(/iPad/i)
|| navigator.userAgent.match(/iPod/i)
|| navigator.userAgent.match(/BlackBerry/i)
|| navigator.userAgent.match(/Windows Phone/i)) {
return true;
} else {
return false;
}
};
/**
* Personal Finance Management SDK
* @constructor
* @param {string} token - Authentication token
* @param {string} env - Environment ('uat' or 'production')
*/
function PFMSDK(token, env) {
let equalDomain = _PFM_APP_URL.uat;
if (token && env) {
if (env.startsWith("production")) {
equalDomain = _PFM_APP_URL.prod;
}
}
/**
* Handles error messages and triggers callbacks
* @param {SDKCallback} callBack - Callback for the error event
* @param {string} statusCode - Error status code
* @param {string} errorMessage - Error message
*/
this.onErrorMessage = (callBack, statusCode, errorMessage) => {
if (callBack != null) {
callBack({ 'eventType': 'PFM_SDK_CALLBACK', 'status': 'ERROR', 'statusCode': statusCode, 'message': errorMessage });
}
if (equalErrorEvent != null) {
equalErrorEvent({ 'eventType': 'PFM_SDK_CALLBACK', 'status': 'ERROR', 'statusCode': statusCode, 'message': errorMessage });
}
}
/**
* Opens the PFM interface
* @param {SDKCallback} onErrorEvent - Callback for error events
* @param {SDKCallback} onCloseEvent - Callback for close events
* @returns {Promise<void>}
*/
this.openPFM = async (onErrorEvent, onCloseEvent) => {
if (_isMobileDevice()) {
this.addMobileViewPort();
}
equalErrorEvent = onErrorEvent;
equalCloseEvent = onCloseEvent;
this.openPFMSDK(null);
}
/**
* Adds mobile viewport meta tag
*/
this.addMobileViewPort = () => {
clientViewPort = document.querySelector("[name='viewport']");
if (clientViewPort != null) {
document.querySelector("[name='viewport']").remove();
}
var metaTag = document.createElement("meta");
metaTag.id = 'equal-viewport';
metaTag.name = "viewport";
metaTag.content =
"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0";
document.getElementsByTagName("head")[0].appendChild(metaTag);
}
/**
* Opens the PFM SDK iframe or popup
* @param {SDKCallback} callBack - Callback for SDK events
* @returns {Promise<void>}
*/
this.openPFMSDK = async (callBack) => {
if (token == null) {
let event = { 'eventType': 'PFM_SDK_CALLBACK', 'status': 'INVALID_SESSION_TOKEN', 'statusCode': "UNKNOWN", 'message': 'INVALID_SESSION_TOKEN' };
equalErrorEvent(event);
window.postMessage(event);
return;
}
const iframeUrl = equalDomain + "/pfm?access_token=" + token;
this.equalRootView = document.createElement('div');
this.equalRootView.id = 'equal-modal';
this.equalRootView.setAttribute("style", "z-index:1500; display:block; padding-top:100px; position:fixed; left:0; top:0; width:100%; height:100%; overflow:auto; background-color:rgb(0,0,0); background-color:rgba(0,0,0,0.4)");
var div = document.createElement('div');
div.id = 'loading';
let width = '480px';
let height = '95%';
if (_isMobileDevice()) {
height = '99%'
width = '99%';
} else {
width = '99%';
height = '99%'
}
if (_isIOSMobile()) {
if ('visualViewport' in window) {
const VIEWPORT_VS_CLIENT_HEIGHT_RATIO = 0.75;
window.visualViewport.addEventListener('resize', function (event) {
if ((event.target.height * event.target.scale) / window.screen.height < VIEWPORT_VS_CLIENT_HEIGHT_RATIO) {
eIframe.contentWindow.postMessage({ 'eventType': 'EQUAL_KEYBOARD_EVENT', 'status': 'OPEN', 'height': (window.outerHeight - window.innerHeight) + 0 }, '*');
} else {
eIframe.contentWindow.postMessage({ 'eventType': 'EQUAL_KEYBOARD_EVENT', 'status': 'CLOSED' }, '*');
}
});
}
}
div.setAttribute("style", "position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); height: " + height + "; width: " + width + "; background: #ffffff; overflow: hidden; border-radius: 8px; cursor: pointer; box-shadow: 0 0 8px 8px rgb(0 0 0 / 10%);");
var eIframe = document.createElement("iframe");
eIframe.id = "pfmIframe"
eIframe.setAttribute("src", iframeUrl);
eIframe.setAttribute("style", "height: 100%; width: 100%;");
eIframe.setAttribute("sandbox", "allow-same-origin allow-scripts allow-forms allow-popups");
eIframe.setAttribute("frameBorder", "0");
div.appendChild(eIframe);
this.equalRootView.appendChild(div);
document.body.appendChild(this.equalRootView);
const messageHandler = (event) => {
console.log(event);
if (event.data.type === 'EXIT_SDK') {
event.data.type = 'PFM_SDK_CALLBACK';
console.log('Iframe URL changed to:', event.data.url);
} else return;
const url = event.data.url;
event.data.url = null;
if (win != null) window.clearInterval(intervalID);
const uri = new URL(url);
const message = uri.searchParams.get('message');
const status_code = uri.searchParams.get('status_code');
const status = uri.searchParams.get('status');
event.data["message"] = message;
event.data["status_code"] = status_code;
event.data["status"] = status;
if (event.data["status"] == "CLOSED") {
if (equalCloseEvent != null) equalCloseEvent(event.data);
window.postMessage(event.data);
} else if (event.data["status"] == "ERROR") {
if (equalErrorEvent != null) equalErrorEvent(event.data);
window.postMessage(event.data);
}
if (this.equalRootView != null) {
if (document.body.contains(this.equalRootView)) {
document.body.removeChild(this.equalRootView);
}
if (document.querySelector("[id='equal-viewport']") != null) {
document.querySelector("[id='equal-viewport']").remove();
}
this.equalRootView = null;
if (this.messageHandler) {
window.removeEventListener('message', this.messageHandler);
this.messageHandler = null;
}
} else if (win != null) {
win.close();
}
};
window.addEventListener('message', messageHandler);
this.messageHandler = messageHandler;
}
}
// Make PFMSDK available for module systems
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = PFMSDK;
} else {
window.PFMSDK = PFMSDK;
}