Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

Added a way to retrieve feedback widget data and manually report them #89

Closed
wants to merge 12 commits into from
Closed
2 changes: 1 addition & 1 deletion .versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
countly:countly-sdk-js@20.11.2
countly:countly-sdk-js@21.11.0
[email protected]
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 21.11.0
* Added a way to retrieve feedback widget data and manually report them for iOS also
* Appear and dismiss callback implemented for nps/survey widgets
* Added "recordIndirectAttribution" method
* Added "recordDirectAttribution" method for Android
* Deprecated recordAttributionID method
* Deprecated enableAttribution method
* Updated minimum supported iOS versions to 10.0
* Updated underlying android SDK to 21.11.0
* Updated underlying iOS SDK to 21.11.1

## 20.11.2
* Moving a push related broadcast receiver declaration to the manifest to comply with 'PendingIntent' checks
* Updated underlying android SDK to 20.11.9
Expand Down
105 changes: 102 additions & 3 deletions Countly.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ Countly = {};
Countly.serverUrl = "";
Countly.appKey = "";
Countly.ready = false;
Countly.version = "20.11.2";
Countly.version = "21.11.0";
Countly.isDebug = false;
Countly.isInitCalled = false;
Countly._appearCallback = Countly.onSuccess;
Countly._dismissCallback = Countly.onSuccess;
Countly.widgetCallback = function(result){
if(result == "appearCallback"){
Countly._appearCallback();
}
else if(result == "dismissCallback"){
Countly._dismissCallback();
}
}
if (window.cordova.platformId == "android") {
Countly.isAndroid = true;
Countly.messagingMode = {"TEST": "2", "PRODUCTION": "0"};
Expand Down Expand Up @@ -560,7 +570,7 @@ Countly.getFeedbackWidgets = function(){
* @param {Object} feedbackWidget - feeback Widget with id, type and name
* @param {String} closeButtonText - text for cancel/close button
*/
Countly.presentFeedbackWidget = function(feedbackWidget, buttonText){
Countly.presentFeedbackWidget = function(feedbackWidget, buttonText, appearCallback, dismissCallback){
if(!feedbackWidget) {
if(Countly.isDebug) {
console.error("[CountlyCordova] presentFeedbackWidget, feedbackWidget should not be null or undefined");
Expand All @@ -579,11 +589,100 @@ Countly.presentFeedbackWidget = function(feedbackWidget, buttonText){
}
return "FeedbackWidget type should not be null or empty";
}
if (appearCallback && (typeof appearCallback == "function")) {
Countly._appearCallback = appearCallback;
}
if (dismissCallback && (typeof dismissCallback == "function")) {
Countly._dismissCallback = dismissCallback;
}
var widgetId = feedbackWidget.id;
var widgetType = feedbackWidget.type;
var widgetName = feedbackWidget.name || "";
buttonText = buttonText || "";
cordova.exec(Countly.onSuccess,Countly.onError,"CountlyCordova","presentFeedbackWidget",[widgetId, widgetType, widgetName, buttonText]);
cordova.exec(Countly.widgetCallback , Countly.onError,"CountlyCordova","presentFeedbackWidget",[widgetId, widgetType, widgetName, buttonText]);
}

/**
* Downloads widget info and returns
* @param {Object} widgetInfo - feeback Widget with id, type and name
*/
Countly.getFeedbackWidgetData = async function(widgetInfo){
if(!widgetInfo) {
if(Countly.isDebug) {
console.error("[CountlyCordova] getFeedbackWidgetData, widgetInfo should not be null or undefined");
}
return "Widget Info should not be null or undefined";
}
if(!widgetInfo.id) {
if(Countly.isDebug){
console.error("[CountlyCordova] getFeedbackWidgetData, widgetInfo id should not be null or empty");
}
return "Widget Info id should not be null or empty";
}
if(!widgetInfo.type) {
if(Countly.isDebug){
console.error("[CountlyCordova] getFeedbackWidgetData, widgetInfo type should not be null or empty");
}
return "Widget Info type should not be null or empty";
}
if(!widgetInfo.name) {
if(Countly.isDebug){
console.error("[CountlyCordova] getFeedbackWidgetData, widgetInfo name should not be null or empty");
}
return "Widget Info name should not be null or empty";
}
var args = [];
args.push(widgetInfo.id);
args.push(widgetInfo.type);
args.push(widgetInfo.name);
return new Promise((resolve,reject) => {
cordova.exec(resolve,reject,"CountlyCordova","getFeedbackWidgetData",args);
});
}

/**
* Report widget info and do data validation
*
* @param {Object} widgetInfo - identifies the specific widget for which the feedback is filled out
* @param {Object} widgetData - widget data for this specific widget
* @param {Object} widgetResult - segmentation of the filled out feedback. If this segmentation is null, it will be assumed that the survey was closed before completion and mark it appropriately
*/
Countly.reportFeedbackWidgetManually = function(widgetInfo, widgetData, widgetResult){
if(!widgetInfo) {
if(Countly.isDebug) {
console.error("[CountlyCordova] reportFeedbackWidgetManually, widgetInfo should not be null or undefined");
}
return "Widget Info should not be null or undefined";
}
if(!widgetInfo.id) {
if(Countly.isDebug){
console.error("[CountlyCordova] reportFeedbackWidgetManually, widgetInfo id should not be null or empty");
}
return "Widget Info id should not be null or empty";
}
if(!widgetInfo.type) {
if(Countly.isDebug){
console.error("[CountlyCordova] reportFeedbackWidgetManually, widgetInfo type should not be null or empty");
}
return "Widget Info type should not be null or empty";
}
if(!widgetInfo.name) {
if(Countly.isDebug){
console.error("[CountlyCordova] reportFeedbackWidgetManually, widgetInfo name should not be null or empty");
}
return "Widget Info name should not be null or empty";
}
var widgetInfoList = [];
widgetInfoList.push(widgetInfo.id);
widgetInfoList.push(widgetInfo.type);
widgetInfoList.push(widgetInfo.name);

var args = [];
args.push(widgetInfoList);
args.push(widgetData);
args.push(widgetResult);

cordova.exec(Countly.onSuccess,Countly.onError,"CountlyCordova","reportFeedbackWidgetManually", args);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions example/cordova_example.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ cordova create app_cordova com.countly.demo app_cordova
cd app_cordova/www

rm index.html
curl https://raw.githubusercontent.com/Countly/countly-sdk-cordova-example/master/app_cordova/www/index.html --output index.html
curl https://raw.githubusercontent.com/Countly/countly-sdk-cordova/master/index.html --output index.html

cordova plugin add https://github.com/Countly/countly-sdk-cordova.git
cordova plugin add https://github.com/Countly/countly-sdk-cordova.git#21.10.0

read -p 'Enter your server URL: ' serverURL
read -p 'Enter your App Key: ' appKey
Expand Down
92 changes: 91 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ <h1 class="ui center aligned header">Countly Cordova Demo App</h1>
<button onclick="app.askForFeedback()" class="fluid ui button orange">Open feedback modal</button>
<button onclick="app.showSurvey()" class="fluid ui button orange">Show Survey</button>
<button onclick="app.showNPS()" class="fluid ui button orange">Show NPS</button>
<button onclick="app.reportNPSManually()" class="fluid ui button orange">Report NPS Manually</button>
<button onclick="app.reportSurveyManually()" class="fluid ui button orange">Report Survey Manually</button>
<div class="ui horizontal divider">Rating Methods End</div>

<div class="ui horizontal divider">Performance Methods Start</div>
Expand Down Expand Up @@ -530,7 +532,13 @@ <h1 class="ui center aligned header">Countly Cordova Demo App</h1>
Countly.getFeedbackWidgets().then((retrivedWidgets) => {
var surveyWidget = retrivedWidgets.find(x => x.type === 'survey')
if(surveyWidget) {
Countly.presentFeedbackWidget(surveyWidget, "Close")
Countly.presentFeedbackWidget(surveyWidget, "Close", function(event){
console.log("appearWidgetCallback");
},
function(event){
console.log("dismissWidgetCallback");
},
)
}
},(err) => {
console.error("showSurvey getFeedbackWidgets error : " +err);
Expand All @@ -548,6 +556,88 @@ <h1 class="ui center aligned header">Countly Cordova Demo App</h1>
});
}

app.reportNPSManually = function() {
Countly.getFeedbackWidgets().then((retrivedWidgets) => {
var npsWidget = retrivedWidgets.find(x => x.type === 'nps')
if(npsWidget) {
Countly.getFeedbackWidgetData(npsWidget).then((retrievedWidgetData) => {
var segments = {
"rating": 3,
"comment": "Filled out comment"
};
Countly.reportFeedbackWidgetManually(
npsWidget, retrievedWidgetData, segments);
},(err) => {
console.error("reportNPSManually getFeedbackWidgetData error : " +err);
});
}
},(err) => {
console.error("reportNPSManually getFeedbackWidgets error : " +err);
});
}

app.reportSurveyManually = function() {
Countly.getFeedbackWidgets().then((retrivedWidgets) => {
var surveyWidget = retrivedWidgets.find(x => x.type === 'survey')
if(surveyWidget) {
Countly.getFeedbackWidgetData(surveyWidget).then((retrievedWidgetData) => {
var segments = {};
if (retrievedWidgetData != null) {
var questions = retrievedWidgetData.questions;

if (questions != null) {
//iterate over all questions and set random answers
for (var a = 0; a < questions.length; a++) {
var question = questions[a];
var wType = question.type;
var questionId = question.id;
var answerKey = 'answ-' + questionId;
switch (wType) {
//multiple answer question
case 'multi':
var choices = question.choices;
var str = '';
for (var b = 0; b < choices.length; b++) {
if (b % 2 == 0) {
if (b != 0) {
str += ',';
}
str += choices[b].key;
}
}
segments[answerKey] = str;
break;
case 'radio':
//dropdown value selector
case 'dropdown':
var choices = question.choices;
var pick = random(choices.length);
segments[answerKey] =
choices[pick].key; //pick the key of random choice
break;
//text input field
case 'text':
segments[answerKey] = 'Some random text';
break;
//rating picker
case 'rating':
segments[answerKey] = random(11);
break;
}
}
}
}
Countly.reportFeedbackWidgetManually(
surveyWidget, retrievedWidgetData, segments);
},(err) => {
console.error("reportSurveyManually getFeedbackWidgetData error : " +err);
});
}
},(err) => {
console.error("reportSurveyManually getFeedbackWidgets error : " +err);
});
}



app.addCrashLog = function() {
Expand Down
2 changes: 1 addition & 1 deletion package.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package.describe({
name: 'countly:countly-sdk-js',
version: '20.11.2',
version: '21.11.0',
summary: 'Countly is an innovative, real-time, open source mobile analytics and push notifications platform. It collects data from mobile devices, and visualizes this information to analyze mobile application usage and end-user behavior. There are two parts of Countly: the server that collects and analyzes data, and mobile SDK that sends this data. Both parts are open source with different licensing terms.',
git: 'https://github.com/Countly/countly-sdk-cordova.git',
documentation: 'README.md'
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "countly-sdk-js",
"version": "20.11.2",
"version": "21.11.0",
"description": "Countly is an innovative, real-time, open source mobile analytics and push notifications platform. It collects data from mobile devices, and visualizes this information to analyze mobile application usage and end-user behavior. There are two parts of Countly: the server that collects and analyzes data, and mobile SDK that sends this data. Both parts are open source with different licensing terms.",
"cordova": {
"id": "countly-sdk-js",
Expand Down
6 changes: 3 additions & 3 deletions plugin.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android" id="countly-sdk-cordova" version="20.11.2">
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android" id="countly-sdk-cordova" version="21.11.0">

<name>Countly Cordova SDK</name>

Expand Down Expand Up @@ -141,11 +141,11 @@

<source-file src="src/android/CountlyCordova.java" target-dir="src/ly/count/android/sdk"/>
<source-file src="src/android/CountlyNative.java" target-dir="src/ly/count/android/sdk"/>
<framework src="ly.count.android:sdk:20.11.9" />
<framework src="ly.count.android:sdk:20.11.10" />

<!-- Push notification -->
<config-file target="AndroidManifest.xml" parent="/manifest/application">
<service android:name="ly.count.android.sdk.CountlyMessagingService">
<service android:name="ly.count.android.sdk.CountlyMessagingService" android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
Expand Down
40 changes: 36 additions & 4 deletions src/android/CountlyCordova.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void pluginInitialize() {
}
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
Context context = this.cordova.getActivity().getApplicationContext();

if ("init".equals(action)) {
callbackContext.success(countlyNative.init(args));
}
Expand Down Expand Up @@ -245,11 +245,11 @@ else if("appLoadingFinished".equals(action)){
callbackContext.success(countlyNative.appLoadingFinished(args));
}
else if ("getFeedbackWidgets".equals(action)) {
countlyNative.getFeedbackWidgets(args, new CountlyNative.JSONObjectCallback() {
countlyNative.getFeedbackWidgets(args, new CountlyNative.JSONArrayCallback() {
@Override
public void success(JSONArray result) {
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK,
result);
result);
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);

Expand All @@ -261,7 +261,39 @@ public void error(String error) {
});
}
else if("presentFeedbackWidget".equals(action)){
PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);
countlyNative.presentFeedbackWidget(args, new CountlyNative.Callback() {
@Override
public void callback(String result) {
if(result.equals("appearCallback") || result.equals("dismissCallback")) {
callbackContext.success(result);
}
else {
callbackContext.error(result);
}
}
});
}
else if ("getFeedbackWidgetData".equals(action)) {
countlyNative.getFeedbackWidgetData(args, new CountlyNative.JSONObjectCallback() {
@Override
public void success(JSONObject result) {
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK,
result);
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);

}
@Override
public void error(String error) {
callbackContext.error(error);
}
});
}
else if("reportFeedbackWidgetManually".equals(action)){
countlyNative.reportFeedbackWidgetManually(args, new CountlyNative.Callback() {
@Override
public void callback(String result) {
callbackContext.success(result);
Expand Down Expand Up @@ -304,7 +336,7 @@ else if("enableApm".equals(action)){
return false;
}
return true;
}
}

@Override
public void onResume(boolean multitasking) {
Expand Down
Loading