Skip to content

Commit

Permalink
Merge pull request #25 from crobox/feature/promotion-response-schema
Browse files Browse the repository at this point in the history
Update ReadME
Clean up redundant optionals from model
Rearrange api documents
  • Loading branch information
toztemel committed Jul 12, 2024
2 parents 5529f04 + f764bd8 commit de93f26
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 163 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ build
.externalNativeBuild
.cxx
local.properties
.kotlin/
108 changes: 99 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# crobox-sdk-android

Crobox SDK for Android

[![Build Status](https://github.com/crobox/crobox-sdk-android/actions/workflows/ci.yml/badge.svg)](https://github.com/crobox/crobox-sdk-android/actions?query=main)
[![Official Crobox project](https://img.shields.io/badge/project-official-green.svg?colorA=303033&colorB=ff8a2c&label=Crobox)](https://crobox.com/)
![GitHub Release](https://img.shields.io/github/v/release/crobox/crobox-sdk-android?include_prereleases)

This is an asynchronous SDK kit for consuming Crobox API for android applications. Written in Kotlin from the ground up.
This is an asynchronous SDK kit for consuming Crobox API for android applications. Written in Kotlin
from the ground up.

First add the dependency to your project:

Expand All @@ -22,9 +24,12 @@ dependencies {
## Start using Crobox SDK

First configure and create a `Crobox` singleton as below, where

- `containerId` should be assigned by Crobox
- `visitorId` should be unique for visitors. It must stay the same across the user's session (or longer if preferred)
- `userId` should optionally be used to link the current visitor with client's user management system, if exists
- `visitorId` should be unique for visitors. It must stay the same across the user's session (or
longer if preferred)
- `userId` should optionally be used to link the current visitor with client's user management
system, if exists

```kotlin
import com.crobox.sdk.common.LocaleCode
Expand All @@ -45,16 +50,18 @@ val croboxInstance = Crobox.getInstance(

```

RequestQueryParams contains page specific parameters, shared by all requests fired from the same page/view.
RequestQueryParams contains page specific parameters, shared by all requests fired from the same
page/view.
It must be recreated when the page/view is displayed.

```kotlin
val overviewPageParams = RequestQueryParams(
viewId = UUID.randomUUID(),
pageType = PageType.PageOverview
)
```

For sending events, use the `xyzEvent` APIs exposed by the Crobox instance.
For sending events, use the `xyzEvent` APIs exposed by the Crobox instance.
Events might also take event specific parameters:

```kotlin
Expand All @@ -71,20 +78,21 @@ croboxInstance.clickEvent(
}

override fun onError(msg: String?) {
Log.d("EventView onError", "" + msg);
Log.d("EventView onError", "" + msg)
}
}
)
```

For retrieving promotions for zero, one or more products, use the specific PlaceholderId that is configured with specific page types and linked to campaigns via Crobox Admin App.
For retrieving promotions for zero, one or more products, use the specific PlaceholderId that is
configured with specific page types and linked to campaigns via Crobox Admin App.

```kotlin

val promotionsCallback = object : PromotionCallback {
override fun onPromotions(response: PromotionsResponse?) { }
override fun onPromotions(response: PromotionsResponse?) {}

override fun onError(msg: String?) { }
override fun onError(msg: String?) {}
}

val impressions: List<String> = listOf("001ABC", "002DEF")
Expand Down Expand Up @@ -112,6 +120,88 @@ croboxInstance.promotions(
)
```

## Promotion Response Schema

```kotlin
object : PromotionCallback {
override fun onPromotions(response: PromotionsResponse) {
val context = response.context
val promotions = response.promotions

val visitorId = context.visitorId
val sessionId = context.sessionId
val groupName = context.groupName ?: ""
for (campaign in context.campaigns) {
val campaignId = campaign.id
val campaignName = campaign.name
val variantId = campaign.variantId
val variantName = campaign.variantName
val control = campaign.control
}

for (promotion in promotions) {
val promotionId = promotion.id
val campaignId = promotion.campaignId
val variantId = promotion.variantId
val productId = promotion.productId ?: ""
promotion.content?.let { content: PromotionContent ->
val messageId = content.messageId
val componentName = content.component
val configMap = content.config
for (c in configMap) {
val configKey = c.key
val configValue = c.value
}
}
}
}
}
```

### PromotionsResponse

| Name | Type | Description |
|------------|------------------|-----------------------------------|
| context | PromotionContext | The context about campaigns |
| promotions | List<Promotion> | The list of promotions calculated |

### PromotionContext

| Name | Type | Description |
|-----------|----------------|--------------------------------------------------|
| sessionId | UUID | Session ID |
| visitorId | UUID | Visitor ID |
| groupName | String? | The list of campaign and variant names, combined |
| campaigns | List<Campaign> | The list of ongoing campaigns |

### Campaign

| Name | Type | Description |
|-------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| id | String | Campaign ID |
| name | String | Campaign Name |
| variantId | String | There is a ratio that determines the amount of traffic exposed to this campaign (or is allocated to the control group) between Crobox and Control group. Variant id refers to the variant which this promotion belongs to and is used for debugging |
| variantName | String | Name of the Campaign Variant |
| control | Boolean | Indicates if the variant is allocated to the control group |

### Promotion

| Name | Type | Description |
|------------|-------------------|------------------------------------------------------|
| id | String | Unique id for this promotion |
| productId | String? | Product ID if requested |
| campaignId | Int | The campaign which this promotion belongs to |
| variantId | Int | ID of the variant that this promotion is assigned to |
| content | PromotionContent? | Promotion Content |

### PromotionContent

| Name | Type | Description |
|-----------|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| messageId | String | As Campaigns might have alternative messages, Message Id identifies the message assigned to this promotion |
| component | String | Component Name |
| config | Map<String, String> | Map of all visual configuration items, managed via Crobox Admin app. <br/>Example:<br/> ```Map("Text1_text" : "Best Seller", "Text1_color" : "#0e1111")``` |

## Samples

See [test app](app/src/main/kotlin/com/crobox/sdk/testapp/MainActivity.kt) for various samples
Expand Down
75 changes: 43 additions & 32 deletions app/src/main/kotlin/com/crobox/sdk/testapp/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package com.crobox.sdk.testapp
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

import com.crobox.sdk.common.CurrencyCode
import com.crobox.sdk.common.LocaleCode
import com.crobox.sdk.core.Crobox
import com.crobox.sdk.config.CroboxConfig
import com.crobox.sdk.core.Crobox
import com.crobox.sdk.data.model.CartQueryParams
import com.crobox.sdk.data.model.ClickQueryParams
import com.crobox.sdk.data.model.ErrorQueryParams
Expand All @@ -23,7 +22,8 @@ class MainActivity : AppCompatActivity() {
private val containerId = "xlrc9t"

// Collection of products/impressions
private val impressions: List<String> = listOf("product1", "product2", "product3", "product4", "product5")
private val impressions: List<String> =
listOf("product1", "product2", "product3", "product4", "product5")
private val productId = impressions.get(0)

// CroboxInstance is the single point of all interactions, keeping the configuration and providing all functionality
Expand Down Expand Up @@ -114,41 +114,52 @@ class MainActivity : AppCompatActivity() {
val stubPromotionCallback = object : PromotionCallback {
val TAG = "PromotionCallback"

override fun onPromotions(response: PromotionsResponse?) {
val campaigns: List<String>? =
response?.context?.campaigns?.map { campaign ->
"Campaign[Id: ${campaign.id}, Name: ${campaign.name}]"
}
override fun onPromotions(response: PromotionsResponse) {
val context = response.context
val promotions = response.promotions

Log.d(
TAG,
val visitorId = context.visitorId
val sessionId = context.sessionId
val campaigns = context.campaigns.map { campaign ->
"Campaign[Id: ${campaign.id}, Name: ${campaign.name}]"
}
val contextStr =
"""
Context [
VisitorId: ${response?.context?.visitorId}
SessionId: ${response?.context?.sessionId}
Campaigns: ${campaigns?.joinToString()}
]
""".trimIndent()
)
Context [
VisitorId: $visitorId,
SessionId: $sessionId
Campaigns: ${campaigns.joinToString()}
]
""".trimIndent()

val promotionsStr = promotions.map { promotion ->
val promotionId = promotion.id
val campaignId = promotion.campaignId
val variantId = promotion.variantId
val productId = promotion.productId ?: ""

response?.promotions?.forEach { promotion ->
Log.d(
TAG,
"""
Promotion[
Id:${promotion.id}
Product:${promotion.productId}
Campaign:${promotion.campaignId}
Variant:${promotion.variantId}
Msg Id:${promotion.content?.id}
Msg Config:${promotion.content?.config}
]
""".trimIndent()
)
"""
Promotion[
Id:$promotionId
Product:$productId
Campaign:$campaignId
Variant:$variantId
Msg Id:${promotion.content?.messageId}
Component:${promotion.content?.component}
Msg Config:${promotion.content?.config}
]
""".trimIndent()
}

Log.d(
TAG, """
context: $contextStr,
promotions: ${promotionsStr.joinToString()}
""".trimIndent()
)
}

override fun onError(msg: String?) {
override fun onError(msg: String) {
Log.d(TAG, "Promotion failed with $msg")
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.crobox.sdk.domain
package com.crobox.sdk.data.api

internal object Constant {
const val API_URL = "https://api.crobox.com"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.crobox.sdk.data.api

import com.crobox.sdk.domain.Constant
import com.google.gson.GsonBuilder
import com.google.gson.Strictness
import okhttp3.OkHttpClient
Expand All @@ -27,7 +26,8 @@ internal object CroboxAPIClient {
}

private fun client(): OkHttpClient {
val client: OkHttpClient = OkHttpClient.Builder().readTimeout(60 * 5, TimeUnit.SECONDS)
val client: OkHttpClient = OkHttpClient.Builder()
.readTimeout(60 * 5, TimeUnit.SECONDS)
.connectTimeout(60 * 5, TimeUnit.SECONDS).build()

return client
Expand Down
44 changes: 31 additions & 13 deletions sdk/src/main/kotlin/com/crobox/sdk/domain/Campaign.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,35 @@ import com.google.gson.annotations.SerializedName

/**
* Represents an ongoing Campaign
*
* @property id Campaign ID
* @property name Campaign Name
* @property variantId Id of the Campaign Variant
* @property variantName Name of the Campaign Variant
* @property control Indicates if variant is allocated to the control group
*/
class Campaign {
@SerializedName("id") val id: String? = null
@SerializedName("name") val name: String? = null
@SerializedName("variantId")val variantId: String? = null
@SerializedName("variantName")val variantName: String? = null
@SerializedName("control")val control: Boolean? = null
}
data class Campaign (
/**
* Campaign ID
*/
@SerializedName("id")
val id: String,

/**
* Campaign Name
*/
@SerializedName("name")
val name: String,

/**
* Id of the Campaign Variant
*/
@SerializedName("variantId")
val variantId: String,

/**
* Name of the Campaign Variant
*/
@SerializedName("variantName")
val variantName: String,

/**
* Indicates if variant is allocated to the control group
*/
@SerializedName("control")
val control: Boolean
)
Loading

0 comments on commit de93f26

Please sign in to comment.