Rendering Widgets

This section describes how widgets are rendered and provides various examples.

Rendering Process

Below are the API commands used per operation.

OperationDescription
Teaser RenderingTeasers operate with a processed response from the server. The API command can be called by the bank and either provided on “startWidget” as payload or requested by the widget if missing from the initialization. The following API are used, according to the implementation:
- getInsights - used to to generate and retrieve insights for the following widgets: carousel, trackersDashboard, hub, singleTeaser, budget related widgets and ACT related widgets
- getInboxInsights - used to generate and retrieve insights for 'inbox' widget
Story RenderingThe story blocks are retrieved using the getInsightDetails API command. The server response is then used to render the blocks. The API command can be called by the bank using either Personetics SDK, or independently by injecting the payload property (as part of the startWidget) into the widget.
Story rating and feedbackThe story widget 'rating' and 'feedback' functionality is implemented using dedicated API calls.
- getInsightRating
- updateInsightRating
- updateInsightFeedback

Example of subscription-widget rendering of the using startWidget API:

  1. Open the widget using a “startWidget” call; widgetType = 'subscription-dashboard', and include all relevant Key Values.
    startWidget ({"widgetType":"subscription-dashboard"})

  2. Following this call, a pre-defined WebView should be opened by the bank, and the widget’s render should be injected to it.

  3. Following this call, a pre-defined WebView should be opened by the bank, and the widget’s render should be injected to it.

  4. In some cases, the startWidget may include additional payload parameters. In that case, the startWidget would include an additional “params” parameter:
    startWidget ({"widgetType":"subscription-dashboard", "params”: {…}})

  5. To display subscription data, the widget sends and API request to the server. The API name is getUserSubscriptions and it should include protocol version. The bank must decide between either options:

    • The request can be sent by the widget, after the “startWidget” initialization, through the delegate function of the widget:
      Personetics Subscription-Dashboard Widget --> Delegate: sendRequestToEnrichServer (requestHeaders, postParam, requestId)
    • by the bank application before the “startWidget” and provided as additional payload once “startWidget” is called:
      Delegate --> PServer API: handleServerResponse (data, requestId)
  6. Following this call, a pre-defined WebView should be opened by the bank, and the widget’s render should be injected to it.

startWidget Examples

This section describes how to use startWidget to render the story-widget and teaser widgets, and provides rendering and response code examples for various layouts.

Inbox Code Examples

Below are inbox widget code examples

JSONObject configurations = new JSONObject();
JSONObject params = new JSONObject();
JSONObject assets = new JSONObject();
JSONObject internationalization = new JSONObject();
JSONObject theme = new JSONObject();
try {
     if(getResources().getBoolean(R.bool.is_use_payload)) {
	      params.put(Personetics.PDB_PAYLOAD, config.get(Personetics.PDB_PAYLOAD));
}
params.put(Personetics.PDB_USER_ID, getResources().getString(R.string.default_user));
configurations.put(Personetics.PDB_WIDGET_TYPE, "inbox");
configurations.put(Personetics.PDB_DEVICE_TYPE, "android");
configurations.put(Personetics.PDB_SELECTOR_STRING, "#root");
configurations.put(Personetics.PDB_PARAMS, params);
if(getResources().getBoolean(R.bool.is_use_remote_assets_mode)) {
    assets.put(Personetics.PDB_BASEURL, getString(R.string.remote_assets));
    assets.put(Personetics.PDB_USEREMOTEASSETS, true);
    }
    internationalization.put(Personetics.PDB_LANGUAGE, "en");
    theme.put(Personetics.PDB_DARKMODE, false);

    config.put(Personetics.PDB_CONFIGURATIONS, configurations);
    config.put(Personetics.PDB_ASSETS, assets);
    config.put(Personetics.PDB_INTERNATIONALIZATION, internationalization);
    config.put(Personetics.PDB_THEME, theme);

    } catch (JSONException e) {
	    e.printStackTrace();
    }

    return ((MainActivity)getActivity()).getPersonetics().startWidgetWithView(getActivity(), config);

let personeticsInfo = NSMutableDictionary.init()
       let personeticsBridge = BankPersoneticsDelegate.init()
       let configurations = NSMutableDictionary.init()
       let params = NSMutableDictionary.init()
       let assets = NSMutableDictionary.init()
       let internationalization = NSMutableDictionary.init()
       let theme = NSMutableDictionary.init()

       guard let constants = NetworkManager.shared.constants else { return }

       params.setValue(constants.userName, forKey: Personetics.PDBuserId)
       configurations.setObject("inbox", forKey: Personetics.PDBWidgetType as NSCopying)
       configurations.setObject("ios", forKey: Personetics.PDBDeviceType as NSCopying)
       configurations.setObject("#root", forKey: Personetics.PDBSelectorString as NSCopying)
       internationalization.setObject(constants.appLanguage, forKey: Personetics.PDBlanguage as NSCopying)
       personeticsBridge.viewCtrl = self

       personeticsInfo.setValue(constants.protocolVersion, forKey: Personetics.PDBprotocolVersion)
       personeticsInfo.setValue(constants.webViewTag, forKey: Personetics.PDBwebViewTag)

       if constants.useRemoteAssets == true {
           assets.setObject(true, forKey: Personetics.PDBuseRemoteAssets as NSCopying)
           assets.setObject(constants.remoteUrl, forKey: Personetics.PDBbaseUrl as NSCopying)
       }
       if constants.darkMode == true {
           theme.setValue(constants.darkMode, forKey: Personetics.PDBdarkMode)
       }
       personeticsInfo.setValue(personeticsBridge, forKey: Personetics.PDBpDelegate  )
       if constants.usePayload {
           if let infoPayload = payload {
               params.setValue(infoPayload, forKey: Personetics.PDBpayload)
           } else {
               getPayloadForType(type: "inbox", requestType: "getInboxInsights", navParams: nil)
               return
           }
       }
       configurations.setObject(params, forKey: Personetics.PDBparams as NSCopying)

       personeticsInfo.setValue(configurations, forKey: Personetics.PDBconfigurations)
       personeticsInfo.setValue(assets, forKey: Personetics.PDBassets)
       personeticsInfo.setValue(internationalization, forKey: Personetics.PDBinternationalization)
       personeticsInfo.setValue(theme, forKey: Personetics.PDBtheme)

       let personetics = Personetics.init()
       personeticsBridge.personetics = personetics
       if let personeticsController = personetics.startWidget(personeticsInfo: personeticsInfo) as? UIViewController {
           personeticsController.updateViewConstraints()
           self.navigationController?.pushViewController(personeticsController, animated: true)
       }
 

startWidget Carousel Example

Below are examples for the carousel widget type. The examples are identical for all teaser widgets, where the widgetType parameter is set according to the widget type.

personetics.startWidget(
{"configurations": {
        "deviceType": "web",
        "ctxId": "dashboard",
        "params": {
            "userId": "B_1012"
        },
        "selectorString": "#root",
        "widgetType": "carousel"
    },
    "assets": {"useRemoteAssets": true
			“baseUrl”: "https://bank-assets.s1.amazonaws.com/clientproduct-assets/assets/"
},
       "internationalization": {
        "language": "en"
    }});

final personeticsInfo_carousel = {
  "protocolVersion": "2.6",
  "internationalization": {"language" “en”},
  "configurations": {
    "widgetType": “carousel”,
    "selectorString": "#root",
    "deviceType": “flutter”,
    "ctxid": “dashboard”,
		  "params": {},
  },
  'widgetHeight': 260,
  'widgetWidth': 320,
};

let personeticsInfo = NSMutableDictionary.init()
       let personeticsBridge = BankPersoneticsDelegate.init()
       let configurations = NSMutableDictionary.init()
       let params = NSMutableDictionary.init()
       let assets = NSMutableDictionary.init()
       let internationalization = NSMutableDictionary.init()
       let theme = NSMutableDictionary.init()

       guard let constants = NetworkManager.shared.constants else { return }

       params.setValue(constants.userName, forKey: Personetics.PDBuserId)
       configurations.setObject("inbox", forKey: Personetics.PDBWidgetType as NSCopying)
       configurations.setObject("ios", forKey: Personetics.PDBDeviceType as NSCopying)
       configurations.setObject("#root", forKey: Personetics.PDBSelectorString as NSCopying)
       internationalization.setObject(constants.appLanguage, forKey: Personetics.PDBlanguage as NSCopying)
       personeticsBridge.viewCtrl = self

       personeticsInfo.setValue(constants.protocolVersion, forKey: Personetics.PDBprotocolVersion)
       personeticsInfo.setValue(constants.webViewTag, forKey: Personetics.PDBwebViewTag)

       if constants.useRemoteAssets == true {
           assets.setObject(true, forKey: Personetics.PDBuseRemoteAssets as NSCopying)
           assets.setObject(constants.remoteUrl, forKey: Personetics.PDBbaseUrl as NSCopying)
       }
       if constants.darkMode == true {
           theme.setValue(constants.darkMode, forKey: Personetics.PDBdarkMode)
       }
       personeticsInfo.setValue(personeticsBridge, forKey: Personetics.PDBpDelegate  )
       if constants.usePayload {
           if let infoPayload = payload {
               params.setValue(infoPayload, forKey: Personetics.PDBpayload)
           } else {
               getPayloadForType(type: "inbox", requestType: "getInboxInsights", navParams: nil)
               return
           }
       }
       configurations.setObject(params, forKey: Personetics.PDBparams as NSCopying)

       personeticsInfo.setValue(configurations, forKey: Personetics.PDBconfigurations)
       personeticsInfo.setValue(assets, forKey: Personetics.PDBassets)
       personeticsInfo.setValue(internationalization, forKey: Personetics.PDBinternationalization)
       personeticsInfo.setValue(theme, forKey: Personetics.PDBtheme)

       let personetics = Personetics.init()
       personeticsBridge.personetics = personetics
       if let personeticsController = personetics.startWidget(personeticsInfo: personeticsInfo) as? UIViewController {
           personeticsController.updateViewConstraints()
           self.navigationController?.pushViewController(personeticsController, animated: true)
       }
 

Note: the ‘selectorString’ example of ‘#root’ corresponds to the sample app example. The relevant path should be defined.

payload Example

Following are payload examples per layout.

Note: For details on 'payload', refer to )[payload Structure](payload-structure.

{
  "configurations": {
    "deviceType": "web",
    "ctxId": "dashboard",
    "params": {
      "payload": {
        "GET_INSIGHTS": {
          "ok": true,
          "protocolVersion": "2.6",
          "requestChannel": "VANILLA_QA",
          "requestType": "getInsights",
          "requestId": "NLjFSETDjW7-K35x",
          "status": "200",
          "statusMessage": "ok",
          "insights": []],
          "numberOfInsights": 8,
          "unreadMessages": 4,
          "numberOfUnreadInsights": 4
        }
      },
      "userId": "B_1012"
    },
    "selectorString": "#root",
    "widgetType": "inbox"
  },
"assets": {
    "baseUrl": https://client-vanilla-assets.s3.amazonaws.com/product-react-assets/assets/,
    "useRemoteAssets": false
  },
  "internationalization": {
    "language": "en"
  },
}

func getPayloadForType(type: String, requestType: String, navParams: NSMutableDictionary?) {
        let serverUrl = NetworkManager.shared.getEngageServerUrl()
        let requestType = requestType
        let requestBodyParams = NSMutableDictionary.init()
        guard let constants = NetworkManager.shared.constants else { return }
 
        requestBodyParams.setValue(requestType, forKey: "type")
        requestBodyParams.setValue("dashboard", forKey: Personetics.PDBctxId)
        requestBodyParams.setValue(constants.protocolVersion, forKey: "protocolVersion")
        requestBodyParams.setValue(constants.appLanguage, forKey: "lang")
        let requestHeaders = NetworkManager.shared.getOptionalReqHeaders()
        NetworkManager.shared.doPostMessage(serverUrl: serverUrl, reqHttpBoday: requestBodyParams,
                                            reqHeaders: requestHeaders, requestType: requestType, onSuccess: { [weak self] result in
            if let payload = result as? String {
                switch type {
                case "story-widget":
                    self?.startStoryWidget(payload: BankUtility.stringToJsonObject(dataString: payload))
                case "inbox":
                    self?.startInboxWidget(payload: BankUtility.stringToJsonObject(dataString: payload))
                case "hub":
                    self?.startHubWidget(payload: BankUtility.stringToJsonObject(dataString: payload))
                case "singleTeaser":
                    self?.startSingleTeaserWidget(payload: BankUtility.stringToJsonObject(dataString: payload))
                case "trackersDashboard":
                    self?.startTrackersDashboardWidget(payload: BankUtility.stringToJsonObject(dataString: payload))
                case "carousel":
                    self?.startCarouselWidget(payload: BankUtility.stringToJsonObject(dataString: payload))
                case "manage-budgets":
                    if let addNavParams = navParams {
                        self?.startBudgetManageWidget(payload: BankUtility
                            .stringToJsonObject(dataString: payload), navParams: addNavParams)
                    } else {
                        self?.startBudgetManageWidget(payload: BankUtility
                            .stringToJsonObject(dataString: payload), navParams: nil)
                    }
                case "subscription-dashboard":
                    if let addNavParams = navParams {
                        self?.startSubscriptionDashboardWidget(payload: BankUtility
                            .stringToJsonObject(dataString: payload), navParams: addNavParams)
                    } else {
                        self?.startSubscriptionDashboardWidget(payload: BankUtility
                            .stringToJsonObject(dataString: payload), navParams: nil)
                    }
                case "actOnboarding":
                    if let addNavParams = navParams{
                        self?.startOnboardingWidget(payload: BankUtility.stringToJsonObject(dataString: payload), navParams: addNavParams)
                    }else{
                        self?.startOnboardingWidget(payload: BankUtility.stringToJsonObject(dataString: payload), navParams:nil)
                    }
                case "actManagement":
                    if let addNavParams = navParams{
                        self?.startManagementWidget(payload: BankUtility.stringToJsonObject(dataString: payload), navParams: addNavParams)
                    }else{
                        self?.startManagementWidget(payload: BankUtility.stringToJsonObject(dataString: payload), navParams:nil)
                    }
                default:
                    break
                }
            } else {
            }
        }, onError: {result in
            print("Get Payload \(requestType) Response ****Failed****: \(String(describing: result)))")
        })
    }

private View populatePersoneticsPriview() {
    JSONObject configurations = new JSONObject();
    JSONObject params = new JSONObject();
    JSONObject assets = new JSONObject();
    JSONObject internationalization = new JSONObject();
    JSONObject theme = new JSONObject();

    try {
        params.put(Personetics.PDB_USER_ID, getResources().getString(R.string.default_user));
        configurations.put(Personetics.PDB_WIDGET_TYPE, "inbox");
        configurations.put(Personetics.PDB_DEVICE_TYPE, "android");
        configurations.put(Personetics.PDB_SELECTOR_STRING, "#root");
        if(getResources().getBoolean(R.bool.is_use_remote_assets_mode)) {
            assets.put(Personetics.PDB_BASEURL, getString(R.string.remote_assets));
            assets.put(Personetics.PDB_USEREMOTEASSETS, true);
        }
        internationalization.put(Personetics.PDB_LANGUAGE, "en");
        theme.put(Personetics.PDB_DARKMODE, false);
        if (getResources().getBoolean(R.bool.is_use_payload)){
            params.put(Personetics.PDB_PAYLOAD,payload);
        }
        configurations.put(Personetics.PDB_PARAMS, params);
        config.put(Personetics.PDB_CONFIGURATIONS, configurations);
        config.put(Personetics.PDB_ASSETS, assets);
        config.put(Personetics.PDB_INTERNATIONALIZATION, internationalization);
        config.put(Personetics.PDB_THEME, theme);

    } catch (JSONException e) {
        e.printStackTrace();
    }
    return  ((MainActivity)getActivity()).getPersonetics().startWidgetWithView(getActivity(), config);
}

The payload variable contains:
payload.put("GET_INBOX_INSIGHTS",jsonResponse);

story-widget Example

story-widget code example

{
	"protocolVersion": "2.6",
   "configurations": {
        "params": {
            "insightId": "dda4db90-76ba-4598-932d-027760271f26",
            "instanceId": "VerifyMailAddress",
          },
        "widgetType": "story-widget",
        "selectorString": "#root",
        "deviceType": "flutter"

    },
    "internationalization": {
        "language": "en"
    }
}
"userId": "ProgramUser_3", // example for userID
    "insightId": "bd165da9-cf04-46da-ad22-1c8844a86454",// example for insightId of a clicked teaser
    "instanceId": "ProgramTracker",", // example for instanceId of a clicked teaser
    "eventType": "teaserClick", 
    "lang": "en", //language
    "clickedTeaser": <elm>  //an element node of the clicked teaser
     teaserId": "perso-teaser-template_bd165da9-cf04-46da-ad22-1c8844a86454" //an id attribute of the clicked teaser
}

Code Examples

Following are code examples, for carousel, trackersDashboard, hub, inbox, and manage-budgets. In each layout, the examples apply to all widget types, as defined under widgetType.

final personeticsInfo_carousel = {
  "protocolVersion": "2.6",
  "internationalization": {"language" “en”},
  "configurations": {
    "widgetType": “carousel”,
    "selectorString": "#root",
    "deviceType": “flutter”,
    "ctxid": “dashboard”,
		  "params": {},
  },
  'widgetHeight': 260,
  'widgetWidth': 320,
};

Note: the ‘selectorString’ example of ‘#root’ corresponds to the sample app example. The relevant path should be defined.