Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Notification Module Analytics #101

Draft
wants to merge 1 commit into
base: 2U/develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/src/main/java/org/openedx/app/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ val appModule = module {
single<WhatsNewRouter> { get<AppRouter>() }
single<AppUpgradeRouter> { get<AppRouter>() }
single<NotificationsRouter> { get<AppRouter>() }

single { DeepLinkRouter(get(), get(), get(), get(), get(), get()) }

single { NetworkConnection(get()) }
Expand Down Expand Up @@ -215,7 +215,7 @@ val appModule = module {
single<IAPAnalytics> { get<AnalyticsManager>() }
single<NotificationsAnalytics> { get<AnalyticsManager>() }

single { PushManager(get(), get()) }
single { PushManager(get(), get(), get()) }
single<PushGlobalManager> { get<PushManager>() }

factory { AgreementProvider(get(), get()) }
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ val screenModule = module {

viewModel { NotificationsInboxViewModel(get(), get(), get(), get()) }
viewModel { NotificationsSettingsViewModel(get(), get(), get(), get()) }
viewModel { NotificationsPrimerViewModel(get(), get()) }
viewModel { NotificationsPrimerViewModel(get(), get(), get()) }

single { IAPRepository(get()) }
factory { IAPInteractor(get(), get(), get(), get(), get()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import androidx.fragment.app.FragmentManager
interface PushGlobalManager {
suspend fun getUnreadNotificationsCount(): Int

fun logNotificationBadgeClickedEvent(hasUnreadNotifications: Boolean)

fun showNotificationsPrimer(context: Context, fragmentManager: FragmentManager)

suspend fun markNotificationAsRead(notificationId: Int)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class LearnViewModel(
}

fun onNotificationBadgeClick(fm: FragmentManager) {
pushManager.logNotificationBadgeClickedEvent(_uiState.value.hasUnreadNotifications)
dashboardRouter.navigateToNotificationsInbox(fm)
_uiState.update { it.copy(hasUnreadNotifications = false) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,37 @@ import org.openedx.core.utils.addDays
import org.openedx.notifications.data.storage.NotificationsPreferences
import org.openedx.notifications.domain.interactor.NotificationsInteractor
import org.openedx.notifications.domain.model.NotificationsPrimerConfiguration
import org.openedx.notifications.presentation.NotificationsAnalytics
import org.openedx.notifications.presentation.NotificationsAnalyticsEvent
import org.openedx.notifications.presentation.NotificationsAnalyticsKey
import org.openedx.notifications.presentation.primer.NotificationsPrimerDialogFragment
import java.util.Date

class PushManager(
private val interactor: NotificationsInteractor,
private val preferences: NotificationsPreferences,
private val analytics: NotificationsAnalytics,
) : PushGlobalManager {

override suspend fun getUnreadNotificationsCount(): Int {
return interactor.getUnreadNotificationsCount().discussion
}

override fun logNotificationBadgeClickedEvent(hasUnreadNotifications: Boolean) {
val event = NotificationsAnalyticsEvent.NOTIFICATIONS_BADGE_CLICKED
analytics.logEvent(
event = event.eventName,
params = buildMap {
put(NotificationsAnalyticsKey.NAME.key, event.biValue)
put(NotificationsAnalyticsKey.UNREAD_NOTIFICATIONS.key, hasUnreadNotifications)
put(
NotificationsAnalyticsKey.CATEGORY.key,
NotificationsAnalyticsKey.NOTIFICATIONS.key
)
}
)
}

override fun showNotificationsPrimer(
context: Context,
fragmentManager: FragmentManager,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,45 @@ interface NotificationsAnalytics {
}

enum class NotificationsAnalyticsEvent(val eventName: String, val biValue: String) {
PUSH_NOTIFICATIONS_SETTINGS(
eventName = "Notification:Push Notifications Settings",
biValue = "edx.bi.app.notification.push_notifications_settings"
),
DISCUSSION_PERMISSION_TOGGLE(
eventName = "Notification:Discussion Permission Toggle",
biValue = "edx.bi.app.notification.discussion.permission.toggle"
),
NOTIFICATIONS_BADGE_CLICKED(
eventName = "Notification:Notification Badge Clicked",
biValue = "edx.bi.app.notification.badge.clicked"
),
NOTIFICATION_INBOX_VIEW(
eventName = "Notification:Notification Inbox",
biValue = "edx.bi.app.notification.inbox"
),
NOTIFICATION_ITEM_TAPPED(
eventName = "Notification:Notification Tapped",
biValue = "edx.bi.app.notification.tapped"
NOTIFICATION_INBOX_ITEM_CLICKED(
eventName = "Notification:Inbox Item Clicked",
biValue = "edx.bi.app.notification.inbox.item.clicked"
),
INBOX_SETTINGS_CLICKED(
eventName = "Notification:Inbox Settings Clicked",
biValue = "edx.bi.app.notification.inbox.settings.clicked"
),
INBOX_MARK_ALL_READ_CLICKED(
eventName = "Notification:Mark All As Read Clicked",
biValue = "edx.bi.app.notification.inbox.mark_all_as_read.clicked"
),
INBOX_PUSH_NOTIFICATIONS_SETTINGS_CLICKED(
eventName = "Notification:Push Notifications Setting Clicked",
biValue = "edx.bi.app.notification.inbox.push_notifications_setting.clicked"
),
NOTIFICATION_PRIMER_VIEWED(
eventName = "Notification:Notification Primer Viewed",
biValue = "edx.bi.app.notification.primer.viewed"
),
NOTIFICATION_PRIMER_ACTION(
eventName = "Notification:Notification Primer Action",
biValue = "edx.bi.app.notification.primer.action"
),
}

Expand All @@ -25,7 +53,11 @@ enum class NotificationsAnalyticsKey(val key: String) {
ACTION("action"),
CATEGORY("category"),
NOTIFICATIONS("notifications"),
NOTIFICATION_CATEGORY("notification_category"),
NOTIFICATION_APP("notification_app"),
DISCUSSION("discussion"),
NOTIFICATION_TYPE("notification_type"),
UNREAD_NOTIFICATIONS("unread_notifications"),
NOTIFY_ME("notify_me"),
NO_THANKS("no_thanks"),
PRIMER_DIALOG_FREQUENCY("dialog_frequency"),
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,10 @@ class NotificationsInboxFragment : Fragment() {
onBackClick = {
requireActivity().supportFragmentManager.popBackStack()
},
onSettingsClick = { menuType ->
onSettingsClick = {
viewModel.logInboxSettingsClicked()
},
onSettingsItemClick = { menuType ->
when (menuType) {
NotificationsMenuType.MARK_ALL_READ -> {
viewModel.markAllNotificationsAsRead()
Expand Down Expand Up @@ -154,7 +157,8 @@ private fun InboxView(
canLoadMore: Boolean,
refreshing: Boolean,
onBackClick: () -> Unit,
onSettingsClick: (NotificationsMenuType) -> Unit,
onSettingsClick: () -> Unit,
onSettingsItemClick: (NotificationsMenuType) -> Unit,
onSwipeRefresh: () -> Unit,
onReloadNotifications: () -> Unit,
paginationCallBack: () -> Unit,
Expand Down Expand Up @@ -215,6 +219,7 @@ private fun InboxView(
modifier = topBarWidth,
onBackClick = onBackClick,
onSettingsClick = onSettingsClick,
onSettingsItemClick = onSettingsItemClick,
)

Surface(
Expand Down Expand Up @@ -311,7 +316,8 @@ private fun InboxView(
private fun Header(
modifier: Modifier = Modifier,
onBackClick: () -> Unit,
onSettingsClick: (NotificationsMenuType) -> Unit,
onSettingsClick: () -> Unit,
onSettingsItemClick: (NotificationsMenuType) -> Unit,
) {
Box(
modifier = modifier
Expand Down Expand Up @@ -339,10 +345,9 @@ private fun Header(
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 16.dp),
onItemClick = onSettingsClick
onSettingsClick = onSettingsClick,
onItemClick = onSettingsItemClick,
)


}
}

Expand All @@ -368,6 +373,7 @@ private fun SectionHeader(
@Composable
private fun NotificationsDropdownMenu(
modifier: Modifier = Modifier,
onSettingsClick: () -> Unit,
onItemClick: (NotificationsMenuType) -> Unit,
) {
var expanded by remember { mutableStateOf(false) }
Expand All @@ -378,6 +384,7 @@ private fun NotificationsDropdownMenu(
Row(
modifier = Modifier
.clickable {
onSettingsClick()
expanded = true
},
verticalAlignment = Alignment.CenterVertically
Expand Down Expand Up @@ -485,6 +492,7 @@ private fun InboxPreview(
refreshing = true,
onBackClick = { },
onSettingsClick = { },
onSettingsItemClick = { },
onSwipeRefresh = { },
onReloadNotifications = { },
paginationCallBack = { },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,6 @@ class NotificationsInboxViewModel(
markNotificationsAsSeen()
}

private fun logScreenViewEvent() {
analytics.logScreenEvent(
screenName = NotificationsAnalyticsEvent.NOTIFICATION_INBOX_VIEW.eventName,
params = buildMap {
put(
NotificationsAnalyticsKey.NAME.key,
NotificationsAnalyticsEvent.NOTIFICATION_INBOX_VIEW.biValue
)
}
)
}

private fun getInboxNotifications() {
_uiState.value = InboxUIState.Loading
internalLoadNotifications()
Expand Down Expand Up @@ -168,17 +156,21 @@ class NotificationsInboxViewModel(
)
}
logEvent(
event = NotificationsAnalyticsEvent.NOTIFICATION_ITEM_TAPPED,
event = NotificationsAnalyticsEvent.NOTIFICATION_INBOX_ITEM_CLICKED,
params = buildMap {
put(
NotificationsAnalyticsKey.NOTIFICATION_TYPE.key,
notification.notificationType
)
put(
NotificationsAnalyticsKey.NOTIFICATION_APP.key,
NotificationsAnalyticsKey.NOTIFICATIONS.key
)
}
)

// Navigating the user to the related post or response in the Course Discussion Tab
if(notification.courseId.isNotEmpty()) {
if (notification.courseId.isNotEmpty()) {
notificationsRouter.navigateToDiscussionThread(
fm = fm,
action = "Topic",
Expand All @@ -200,6 +192,15 @@ class NotificationsInboxViewModel(
}

fun markAllNotificationsAsRead() {
logEvent(
event = NotificationsAnalyticsEvent.INBOX_MARK_ALL_READ_CLICKED,
params = buildMap {
put(
NotificationsAnalyticsKey.NOTIFICATION_APP.key,
NotificationsAnalyticsKey.DISCUSSION.key
)
},
)
viewModelScope.launch {
try {
if (_uiState.value is InboxUIState.Data) {
Expand All @@ -220,9 +221,14 @@ class NotificationsInboxViewModel(
}

fun navigateToPushNotificationsSettings(fm: FragmentManager) {
logEvent(NotificationsAnalyticsEvent.INBOX_PUSH_NOTIFICATIONS_SETTINGS_CLICKED)
notificationsRouter.navigateToPushNotificationsSettings(fm)
}

fun logInboxSettingsClicked() {
logEvent(NotificationsAnalyticsEvent.INBOX_SETTINGS_CLICKED)
}

private suspend fun emitErrorMessage(e: Exception) {
if (e.isInternetError()) {
_uiMessage.emit(
Expand All @@ -235,18 +241,31 @@ class NotificationsInboxViewModel(
}
}

private fun logEvent(event: NotificationsAnalyticsEvent, params: Map<String, Any?>) {
analytics.logEvent(
event = event.eventName,
private fun logScreenViewEvent() {
val event = NotificationsAnalyticsEvent.NOTIFICATION_INBOX_VIEW
analytics.logScreenEvent(
screenName = event.eventName,
params = buildMap {
put(NotificationsAnalyticsKey.NAME.key, event.biValue)
put(
NotificationsAnalyticsKey.CATEGORY.key,
NotificationsAnalyticsKey.NOTIFICATIONS.key
)
}
)
}

private fun logEvent(
event: NotificationsAnalyticsEvent,
params: Map<String, Any?> = emptyMap(),
) {
analytics.logEvent(
event = event.eventName,
params = buildMap {
put(NotificationsAnalyticsKey.NAME.key, event.biValue)
put(
NotificationsAnalyticsKey.NOTIFICATION_CATEGORY.key,
NotificationsAnalyticsKey.DISCUSSION.key
NotificationsAnalyticsKey.CATEGORY.key,
NotificationsAnalyticsKey.NOTIFICATIONS.key
)
putAll(params)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import org.openedx.core.ui.theme.OpenEdXTheme
import org.openedx.core.ui.theme.appColors
import org.openedx.core.ui.theme.appTypography
import org.openedx.notifications.R
import org.openedx.notifications.presentation.NotificationsAnalyticsKey
import org.openedx.notifications.utils.PermissionUtils

class NotificationsPrimerDialogFragment : DialogFragment() {
Expand Down Expand Up @@ -79,9 +80,11 @@ class NotificationsPrimerDialogFragment : DialogFragment() {
PrimerUIState.ShowDialog -> {
NotificationsPrimer(
onDismissRequest = {
viewModel.logPrimerActionEvent(NotificationsAnalyticsKey.NO_THANKS)
viewModel.dismissDialog()
},
onNotifyClick = {
viewModel.logPrimerActionEvent(NotificationsAnalyticsKey.NOTIFY_ME)
viewModel.hideDialog()
PermissionUtils.requestNotificationPermission(
activity = requireActivity(),
Expand Down
Loading