Skip to content

Commit

Permalink
feat(deriv_auth): add log in user tracking events. (#620)
Browse files Browse the repository at this point in the history
  • Loading branch information
naif-deriv authored Jun 25, 2024
1 parent b0b66da commit ae9556c
Show file tree
Hide file tree
Showing 16 changed files with 537 additions and 8 deletions.
164 changes: 164 additions & 0 deletions packages/deriv_auth/lib/core/analytics/data/auth_tracking_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import 'package:deriv_auth/core/analytics/enums.dart';

/// Get user tracking data.
Map<String, dynamic> getUserTrackingData(
LoginAction action,
String appId, {
LoginProvider? provider,
String? errorMessage,
}) =>
switch (action) {
LoginAction.openLoginForm => <String, dynamic>{
'event': 'open',
'properties': <String, String>{
'app_id': appId,
},
},
LoginAction.startLogin => _getLoginStartedTrackingData(
provider,
appId,
),
LoginAction.finishLogin => _getLoginFinishedTrackingData(
provider,
appId,
),
LoginAction.loginError => _getLoginErrorTrackingData(
provider,
appId,
errorMessage ?? (throw Exception('Error message is required.')),
),
};

/// Get login started tracking data.
Map<String, dynamic> _getLoginStartedTrackingData(
LoginProvider? provider, String appId) =>
switch (provider) {
LoginProvider.email => <String, dynamic>{
'event': 'login_started',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'email',
},
},
LoginProvider.passkey => <String, dynamic>{
'event': 'login_started',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'passkey',
},
},
LoginProvider.google => <String, dynamic>{
'event': 'login_started',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'google',
},
},
LoginProvider.facebook => <String, dynamic>{
'event': 'login_started',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'facebook',
},
},
LoginProvider.apple => <String, dynamic>{
'event': 'login_started',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'apple',
},
},
null => throw Exception('Null LoginProvider is being passed.'),
};

/// Get login finished tracking data.
Map<String, dynamic> _getLoginFinishedTrackingData(
LoginProvider? provider, String appId) =>
switch (provider) {
LoginProvider.email => <String, dynamic>{
'event': 'login_finished',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'email',
},
},
LoginProvider.passkey => <String, dynamic>{
'event': 'login_finished',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'passkey',
},
},
LoginProvider.google => <String, dynamic>{
'event': 'login_finished',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'google',
},
},
LoginProvider.facebook => <String, dynamic>{
'event': 'login_finished',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'facebook',
},
},
LoginProvider.apple => <String, dynamic>{
'event': 'login_finished',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'apple',
},
},
null => throw Exception('Null LoginProvider is being passed.'),
};

/// Get login error tracking data.
Map<String, dynamic> _getLoginErrorTrackingData(
LoginProvider? provider,
String appId,
String errorMessage,
) =>
switch (provider) {
LoginProvider.email => <String, dynamic>{
'event': 'login_flow_error',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'email',
'error_message': errorMessage,
},
},
LoginProvider.passkey => <String, dynamic>{
'event': 'login_flow_error',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'passkey',
'error_message': errorMessage,
},
},
LoginProvider.google => <String, dynamic>{
'event': 'login_flow_error',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'google',
'error_message': errorMessage,
},
},
LoginProvider.facebook => <String, dynamic>{
'event': 'login_flow_error',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'facebook',
'error_message': errorMessage,
},
},
LoginProvider.apple => <String, dynamic>{
'event': 'login_flow_error',
'properties': <String, dynamic>{
'app_id': appId,
'login_provider': 'apple',
'error_message': errorMessage,
},
},
null => throw Exception('Null LoginProvider is being passed.'),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import 'package:analytics/sdk/rudderstack/sdk/deriv_rudderstack_sdk.dart';
import 'package:deriv_auth/core/services/token/models/enums.dart';
import 'package:deriv_auth/core/analytics/data/auth_tracking_data.dart';
import 'package:deriv_auth/core/analytics/domain/auth_user_tracking_interface.dart';
import 'package:deriv_auth/core/analytics/enums.dart';

/// Repository to track user events.
class AuthTrackingRepository implements AuthUserTrackingInterface {
/// Constructor for [AnalyticsRepository].
AuthTrackingRepository._(
this._appId,
this._derivRudderstack,
);

static AuthTrackingRepository? _instance;

/// Singleton instance of [AnalyticsRepository].
static AuthTrackingRepository get instance => _instance ??=
throw Exception('AuthTrackingRepository is not initialized');

/// Instance of [DerivRudderstack].
final DerivRudderstack _derivRudderstack;

/// Initialize [AnalyticsRepository].
static void init(
String appId, {
required DerivRudderstack derivRudderstack,
}) =>
_instance = AuthTrackingRepository._(
appId,
derivRudderstack,
);

/// Deriv client app ID.
final String _appId;

LoginProvider? _loginProvider;

@override
void trackUserOpenedLoginForm() {
final Map<String, dynamic> data = getUserTrackingData(
LoginAction.openLoginForm,
_appId,
);

_derivRudderstack.track(
eventName: data['event'] as String,
properties: data['properties'] as Map<String, dynamic>,
);
}

@override
void trackError(String errorMessage) {
final Map<String, dynamic> data = getUserTrackingData(
LoginAction.loginError,
_appId,
errorMessage: errorMessage,
);

_derivRudderstack.track(
eventName: data['event'] as String,
properties: data['properties'] as Map<String, dynamic>,
);
}

@override
void trackSystemLoginPressed() {
final Map<String, dynamic> data = getUserTrackingData(
LoginAction.startLogin,
_appId,
provider: LoginProvider.email,
);

_loginProvider = LoginProvider.email;

_derivRudderstack.track(
eventName: data['event'] as String,
properties: data['properties'] as Map<String, dynamic>,
);
}

@override
void trackPasskeyLoginPressed() {
final Map<String, dynamic> data = getUserTrackingData(
LoginAction.startLogin,
_appId,
provider: LoginProvider.passkey,
);

_loginProvider = LoginProvider.passkey;

_derivRudderstack.track(
eventName: data['event'] as String,
properties: data['properties'] as Map<String, dynamic>,
);
}

@override
void trackSocialLoginPressed(SocialAuthProvider type) {
_loginProvider = switch (type) {
SocialAuthProvider.google => LoginProvider.google,
SocialAuthProvider.facebook => LoginProvider.facebook,
SocialAuthProvider.apple => LoginProvider.apple,
};

final Map<String, dynamic> data = getUserTrackingData(
LoginAction.startLogin,
_appId,
provider: _loginProvider,
);

_derivRudderstack.track(
eventName: data['event'] as String,
properties: data['properties'] as Map<String, dynamic>,
);
}

@override
void trackLoginFinished() {
final Map<String, dynamic> data = getUserTrackingData(
LoginAction.finishLogin,
_appId,
provider: _loginProvider,
);

_derivRudderstack.track(
eventName: data['event'] as String,
properties: data['properties'] as Map<String, dynamic>,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:deriv_auth/deriv_auth.dart';

/// Interface to define the methods for tracking user events.
abstract interface class AuthUserTrackingInterface {
/// Track user opened login form.
void trackUserOpenedLoginForm();

/// Track user clicks log after entering email and password.
void trackSystemLoginPressed();

/// Track user clicks on Passkey login button.
void trackPasskeyLoginPressed();

/// Track user clicks on social login button.
void trackSocialLoginPressed(
SocialAuthProvider type,
);

/// Track login finished.
void trackLoginFinished();

/// Track login error.
void trackError(String errorMessage);
}
32 changes: 32 additions & 0 deletions packages/deriv_auth/lib/core/analytics/enums.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/// Enum for login actions
enum LoginAction {
/// Open login form.
openLoginForm,

/// Start system login.
startLogin,

/// Finish login.
finishLogin,

/// Login error.
loginError,
}

/// Enum for login provider.
enum LoginProvider {
/// Email login.
email,

/// Passkey login.
passkey,

/// Google login.
google,

/// Facebook login.
facebook,

/// Apple login.
apple,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'package:deriv_auth/deriv_auth.dart';
import 'package:deriv_auth/core/analytics/data/auth_tracking_repository.dart';

/// Mixin for tracking user authentication actions.
mixin AuthTrackingMixin {
late final AuthTrackingRepository _repository =
AuthTrackingRepository.instance;

/// Track user opened login form.
void trackUserOpenedLoginForm() => _repository.trackUserOpenedLoginForm();

/// Track login error.
void trackError(String errorMessage) => _repository.trackError(errorMessage);

/// Track login started.
void trackLoginWithEmailAndPassword() =>
_repository.trackSystemLoginPressed();

/// Track Passkey login started.
void trackLoginWithPasskey() => _repository.trackPasskeyLoginPressed();

/// Track Google login started.
void trackLoginWithGoogle() =>
_repository.trackSocialLoginPressed(SocialAuthProvider.google);

/// Track Facebook login started.
void trackLoginWithFacebook() =>
_repository.trackSocialLoginPressed(SocialAuthProvider.facebook);

/// Track Apple login started.
void trackLoginWithApple() =>
_repository.trackSocialLoginPressed(SocialAuthProvider.apple);

/// Track login finished.
void trackLoginFinished() => _repository.trackLoginFinished();
}
Loading

0 comments on commit ae9556c

Please sign in to comment.