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

chore: improve analytics for sign up and sign in flows #118

Open
wants to merge 2 commits into
base: 2U/develop
Choose a base branch
from
Open
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
6 changes: 3 additions & 3 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha }}

- uses: actions/cache@v3
- uses: actions/cache@v4
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
Expand All @@ -43,7 +43,7 @@ jobs:
run: bundle exec fastlane unit_tests

- name: Archive artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: always()
with:
name: test-output
Expand All @@ -52,6 +52,6 @@ jobs:
if-no-files-found: ignore

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
flags: unittests
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ public protocol AuthorizationAnalytics {
func userLogin(method: AuthMethod)
func registerClicked()
func signInClicked()
func userSignInClicked()
func createAccountClicked()
func userSignInClicked(method: String)
func socialRegisterClicked(method: String)
func createAccountClicked(method: String)
func registrationSuccess(method: String)
func socialAuthFailure(method: String, errorCode: String?, errorMessage: String?)
func registerFailure(method: String, errorCode: String?, errorMessage: String?)
func signInFailure(method: String, errorCode: String?, errorMessage: String?)
func forgotPasswordClicked()
func resetPasswordClicked()
func resetPassword(success: Bool)
Expand All @@ -50,9 +54,13 @@ class AuthorizationAnalyticsMock: AuthorizationAnalytics {
public func userLogin(method: AuthMethod) {}
public func registerClicked() {}
public func signInClicked() {}
public func userSignInClicked() {}
public func createAccountClicked() {}
public func userSignInClicked(method: String) {}
public func socialRegisterClicked(method: String) {}
public func createAccountClicked(method: String) {}
public func registrationSuccess(method: String) {}
public func socialAuthFailure(method: String, errorCode: String?, errorMessage: String?) {}
public func registerFailure(method: String, errorCode: String?, errorMessage: String?) {}
public func signInFailure(method: String, errorCode: String?, errorMessage: String?) {}
public func forgotPasswordClicked() {}
public func resetPasswordClicked() {}
public func resetPassword(success: Bool) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,7 @@ public struct SignInView: View {

if viewModel.socialAuthEnabled {
SocialAuthView(
viewModel: .init(
config: viewModel.config,
lastUsedOption: viewModel.storage.lastUsedSocialAuth
) { result in
Task { await viewModel.login(with: result) }
}
viewModel: viewModel.socialAuthViewModel
)
.padding(.top, 22)
.padding(.bottom, 16)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ public class SignInViewModel: ObservableObject {
config.microsoft.enabled ||
config.google.enabled
}

lazy var socialAuthViewModel = SocialAuthViewModel(
config: config,
analytics: analytics,
authType: .signIn,
lastUsedOption: storage.lastUsedSocialAuth,
completion: { [weak self] method, result in
guard let self else { return }

Task {
await self.login(with: method, result: result)
}
}
)

@MainActor
func login(username: String, password: String) async {
Expand All @@ -78,7 +92,7 @@ public class SignInViewModel: ObservableObject {
errorMessage = AuthLocalization.Error.invalidPasswordLenght
return
}
analytics.userSignInClicked()
analytics.userSignInClicked(method: AuthMethod.password.analyticsValue)
isShowProgress = true
do {
let user = try await interactor.login(username: username, password: password)
Expand All @@ -87,12 +101,12 @@ public class SignInViewModel: ObservableObject {
router.showMainOrWhatsNewScreen(sourceScreen: sourceScreen, postLoginData: nil)
NotificationCenter.default.post(name: .userAuthorized, object: nil)
} catch let error {
failure(error)
failure(error, authMethod: .password)
}
}

@MainActor
func login(with result: Result<SocialAuthDetails, Error>) async {
func login(with method: SocialAuthMethod, result: Result<SocialAuthDetails, SocialAuthError>) async {
switch result {
case .success(let result):
await socialLogin(
Expand All @@ -101,6 +115,11 @@ public class SignInViewModel: ObservableObject {
authMethod: result.authMethod
)
case .failure(let error):
analytics.signInFailure(
method: AuthMethod.socailAuth(method).analyticsValue,
errorCode: error.errorCode.flatMap { String($0) },
errorMessage: error.errorDescription
)
errorMessage = error.localizedDescription
}
}
Expand Down Expand Up @@ -128,11 +147,11 @@ public class SignInViewModel: ObservableObject {
}

@MainActor
private func failure(_ error: Error, authMethod: AuthMethod? = nil) {
private func failure(_ error: Error, authMethod: AuthMethod) {
isShowProgress = false
if let validationError = error.validationError,
let value = validationError.data?["error_description"] as? String {
if authMethod != .password, validationError.statusCode == 400, let authMethod = authMethod {
if authMethod != .password, validationError.statusCode == 400 {
errorMessage = AuthLocalization.Error.accountNotRegistered(
authMethod.analyticsValue,
config.platformName
Expand All @@ -149,6 +168,12 @@ public class SignInViewModel: ObservableObject {
} else {
errorMessage = CoreLocalization.Error.unknownError
}

analytics.signInFailure(
method: authMethod.analyticsValue,
errorCode: nil,
errorMessage: errorMessage
)
}

func trackForgotPasswordClicked() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,7 @@ public struct SignUpView: View {
if viewModel.socialAuthEnabled,
!requiredFields.isEmpty {
SocialAuthView(
authType: .register,
viewModel: .init(
config: viewModel.config,
lastUsedOption: viewModel.storage.lastUsedSocialAuth
) { result in
Task { await viewModel.register(with: result) }
}
viewModel: viewModel.socialAuthViewModel
)
.padding(.top, 22)
.padding(.bottom, -2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ public class SignUpViewModel: ObservableObject {
config.google.enabled
return socialLoginEnabled && !thirdPartyAuthSuccess && !isShowProgress
}

lazy var socialAuthViewModel = SocialAuthViewModel(
config: config,
analytics: analytics,
authType: .register,
lastUsedOption: storage.lastUsedSocialAuth,
completion: { [weak self] method, result in
guard let self else { return }

Task {
await self.register(with: method, result: result)
}
}
)

private func showErrors(errors: [String: String]) -> Bool {
if thirdPartyAuthSuccess, !errors.map({ $0.value }).filter({ !$0.isEmpty }).isEmpty {
Expand Down Expand Up @@ -153,6 +167,12 @@ public class SignUpViewModel: ObservableObject {
} else {
errorMessage = CoreLocalization.Error.unknownError
}

analytics.registerFailure(
method: authMetod.analyticsValue,
errorCode: nil,
errorMessage: errorMessage
)
}
}

Expand All @@ -174,7 +194,7 @@ public class SignUpViewModel: ObservableObject {
}

@MainActor
func register(with result: Result<SocialAuthDetails, Error>) async {
func register(with method: SocialAuthMethod, result: Result<SocialAuthDetails, SocialAuthError>) async {
switch result {
case .success(let result):
await loginOrRegister(
Expand All @@ -183,6 +203,11 @@ public class SignUpViewModel: ObservableObject {
authMethod: result.authMethod
)
case .failure(let error):
analytics.socialAuthFailure(
method: AuthMethod.socailAuth(method).analyticsValue,
errorCode: error.errorCode.flatMap { String($0) },
errorMessage: error.errorDescription
)
errorMessage = error.localizedDescription
}
}
Expand Down Expand Up @@ -222,7 +247,7 @@ public class SignUpViewModel: ObservableObject {
}

func trackCreateAccountClicked() {
analytics.createAccountClicked()
analytics.createAccountClicked(method: authMethod.analyticsValue)
}

func trackScreenEvent() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,26 @@ import SwiftUI
import Core
import Theme

enum SocialAuthType {
case signIn
case register
}

struct SocialAuthView: View {

// MARK: - Properties
@StateObject var viewModel: SocialAuthViewModel

init(
authType: SocialAuthType = .signIn,
viewModel: SocialAuthViewModel
) {
init(viewModel: SocialAuthViewModel) {
self._viewModel = .init(wrappedValue: viewModel)
self.authType = authType
}

enum SocialAuthType {
case signIn
case register
}
var authType: SocialAuthType = .signIn

private var title: String {
AuthLocalization.continueWith
}

private var bottomViewText: String {
switch authType {
switch viewModel.authType {
case .signIn:
AuthLocalization.orSignInWith
case .register:
Expand Down Expand Up @@ -64,7 +59,7 @@ struct SocialAuthView: View {
private var buttonsView: some View {
HStack {
if let lastOption = viewModel.lastUsedOption,
authType == .signIn {
viewModel.authType == .signIn {
Text(AuthLocalization.lastSignIn)
.font(Theme.Fonts.bodySmall)
.foregroundStyle(Theme.Colors.textPrimary)
Expand All @@ -83,7 +78,7 @@ struct SocialAuthView: View {

HStack {
ForEach(viewModel.enabledOptions, id: \.self) { option in
if option != viewModel.lastUsedOption || authType != .signIn {
if option != viewModel.lastUsedOption || viewModel.authType != .signIn {
socialAuthButton(option)
.padding(.trailing, option == viewModel.enabledOptions.last ? 0 : 12)
}
Expand Down Expand Up @@ -145,8 +140,10 @@ struct SocialSignView_Previews: PreviewProvider {
static var previews: some View {
let vm = SocialAuthViewModel(
config: ConfigMock(),
analytics: AuthorizationAnalyticsMock(),
authType: .signIn,
lastUsedOption: nil,
completion: { _ in }
completion: { _, _ in }
)
SocialAuthView(viewModel: vm).padding()
}
Expand Down
Loading
Loading