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: brij error handling #1651

Merged
merged 11 commits into from
Jan 13, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ class KycRepository extends ChangeNotifier {
return await _initWrapper(
() => _getUserData(includeValues: includeValues),
);
} on Exception {
} on Exception catch (exception) {
reportError(exception);

return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore_for_file: avoid-wildcard-cases-with-enums

import 'package:flutter/material.dart';

import '../../../di.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore_for_file: avoid-wildcard-cases-with-enums
justinenerio marked this conversation as resolved.
Show resolved Hide resolved

import 'package:flutter/material.dart';

import '../../../di.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,109 @@
import 'package:dio/dio.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../../utils/errors.dart';

part 'kyc_exception.freezed.dart';

@freezed
sealed class KycException with _$KycException implements Exception {
const factory KycException.invalidCode() = KycInvalidCode;
const factory KycException.invalidEmail() = KycInvalidEmail;
const factory KycException.invalidPhone() = KycInvalidPhone;
const factory KycException.invalidData() = KycInvalidData;
// Phone verification errors
const factory KycException.phone(PhoneError error) = KycPhoneError;

// Email verification errors
const factory KycException.email(EmailError error) = KycEmailError;

// Generic KYC errors
const factory KycException.invalidToken() = KycInvalidToken;
const factory KycException.invalidData() = KycInvalidData;
const factory KycException.genericError() = KycGenericError;
const factory KycException.invalid() = KycInvalid;
const factory KycException.invalidCode() = KycInvalidCode;
}

enum PhoneError {
blocked,
fraudBlock,
tooManyAttempts,
undeliverable,
}

enum EmailError {
blocked,
bounced,
spam,
}

extension ErrorExt on Exception {
KycException toKycException() {
if (this is! DioException) {
reportError(this, StackTrace.current);

return const KycException.genericError();
}

final dioException = this as DioException;
final message = (dioException.response?.data
as Map<String, dynamic>?)?['message'] as String?;
final code =
(dioException.response?.data as Map<String, dynamic>?)?['code'] as int?;

if (message == null) {
reportError(dioException, StackTrace.current);

return const KycException.genericError();
}

// Phone-related Twilio errors
if (code == 2) {
final exception = switch (message) {
final s when s.contains('60203') =>
justinenerio marked this conversation as resolved.
Show resolved Hide resolved
const KycException.phone(PhoneError.tooManyAttempts),
final s when s.contains('60200') => const KycException.invalid(),
final s when s.contains('60022') =>
const KycException.phone(PhoneError.blocked),
final s when s.contains('60033') =>
const KycException.phone(PhoneError.undeliverable),
final s when s.contains('60410') =>
const KycException.phone(PhoneError.fraudBlock),
_ => const KycException.genericError(),
};

if (exception is KycGenericError) {
reportError(dioException, StackTrace.current);
}

return exception;
}

// Email and generic validation errors
final exception = code == 400
? switch (message) {
final s when s.contains('550 5.7.1') =>
const KycException.email(EmailError.blocked),
final s when s.contains('550 5.1.1') =>
const KycException.email(EmailError.bounced),
final s when s.contains('553 5.7.1') =>
const KycException.email(EmailError.spam),
_ => const KycException.genericError(),
}
: switch (message) {
final s when s.contains('invalid token') =>
const KycException.invalidToken(),
final s when s.contains('invalid email') =>
const KycException.invalid(),
final s when s.contains('invalid phone') =>
const KycException.invalid(),
final s when s.contains('invalid code') =>
const KycException.invalidCode(),
final s when s.contains('invalid data') =>
const KycException.invalidData(),
_ => const KycException.genericError(),
};

if (exception is KycGenericError) {
reportError(dioException, StackTrace.current);
}

return switch (message) {
'invalid token' => const KycException.invalidToken(),
'invalid email' => const KycException.invalidEmail(),
'invalid phone' => const KycException.invalidPhone(),
'invalid code' => const KycException.invalidCode(),
'invalid data' => const KycException.invalidData(),
_ => const KycException.genericError(),
};
return exception;
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore_for_file: avoid-wildcard-cases-with-enums
justinenerio marked this conversation as resolved.
Show resolved Hide resolved

import 'package:flutter/material.dart';

import '../../../di.dart';
Expand All @@ -23,7 +25,12 @@ extension KycBuildContext on BuildContext {
if (!mounted) return false;

final message = switch (error) {
KycInvalidEmail() => context.l10n.invalidEmail,
KycInvalidCode() => context.l10n.invalidEmail,
KycEmailError(:final error) => switch (error) {
EmailError.blocked => context.l10n.emailBlocked,
EmailError.bounced => context.l10n.emailBounced,
EmailError.spam => context.l10n.emailSpam,
},
_ => context.l10n.failedToSendVerificationCode,
};

Expand All @@ -49,7 +56,14 @@ extension KycBuildContext on BuildContext {
if (!mounted) return false;

final message = switch (error) {
KycInvalidPhone() => context.l10n.invalidPhone,
KycInvalidCode() => context.l10n.wrongVerificationCode,
KycPhoneError(:final error) => switch (error) {
PhoneError.blocked => context.l10n.phoneBlocked,
PhoneError.fraudBlock => context.l10n.phoneFraudBlock,
PhoneError.tooManyAttempts =>
context.l10n.phoneTooManyAttempts,
PhoneError.undeliverable => context.l10n.phoneUndeliverable,
},
_ => context.l10n.failedToSendVerificationCode,
};

Expand Down
20 changes: 17 additions & 3 deletions packages/espressocash_app/lib/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1203,7 +1203,21 @@
"pendingKycDialogTitle": "We’re still verifying your *identity.*",
"@pendingKycDialogTitle": {},
"pendingKycDialogMessage": "Your identity verification is currently under review and will be completed shortly. You can check the Activity page for real-time updates on your verification status.",
"@pendingKycDialogMessage": {},
"@pendingKycDialogMessage": {},
"continueVerification": "Continue Verification",
"@continueVerification": {}
}
"@continueVerification": {},
"emailBlocked": "This email address has been blocked",
"@emailBlocked": {},
"emailBounced": "This email address is invalid or no longer exists",
"@emailBounced": {},
"emailSpam": "This email address has been marked as spam",
"@emailSpam": {},
"phoneBlocked": "This phone number has been blocked",
"@phoneBlocked": {},
"phoneFraudBlock": "This phone number has been flagged for suspicious activity",
"@phoneFraudBlock": {},
"phoneTooManyAttempts": "Too many verification attempts. Please try again later",
"@phoneTooManyAttempts": {},
"phoneUndeliverable": "Unable to deliver to this phone number",
"@phoneUndeliverable": {}
}
Loading