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(deriv_auth): add log in user tracking events. #620

Merged
Merged
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
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
Loading