From 4cf1702c7647db359fd64343ff37638651d3d98e Mon Sep 17 00:00:00 2001 From: Justin Enerio Date: Fri, 20 Dec 2024 13:26:36 +0800 Subject: [PATCH 1/6] upd --- .../kyc_sharing/data/kyc_repository.dart | 4 +- .../screens/email_confirmation_screen.dart | 2 + .../screens/phone_confirmation_screen.dart | 2 + .../kyc_sharing/utils/kyc_exception.dart | 98 ++++++++++++++++--- .../kyc_sharing/widgets/extensions.dart | 18 +++- 5 files changed, 109 insertions(+), 15 deletions(-) diff --git a/packages/espressocash_app/lib/features/kyc_sharing/data/kyc_repository.dart b/packages/espressocash_app/lib/features/kyc_sharing/data/kyc_repository.dart index cb1367e81..ec027c4e2 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/data/kyc_repository.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/data/kyc_repository.dart @@ -64,7 +64,9 @@ class KycRepository extends ChangeNotifier { return await _initWrapper( () => _getUserData(includeValues: includeValues), ); - } on Exception { + } on Exception catch (exception) { + reportError(exception); + return null; } } diff --git a/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart b/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart index ac56db2f4..3060291d3 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid-wildcard-cases-with-enums + import 'package:flutter/material.dart'; import '../../../di.dart'; diff --git a/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart b/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart index 2987fc6c8..b8f155b01 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid-wildcard-cases-with-enums + import 'package:flutter/material.dart'; import '../../../di.dart'; diff --git a/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart b/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart index b78aaa0b3..9ba173d75 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart @@ -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?)?['message'] as String?; + final code = + (dioException.response?.data as Map?)?['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') => + 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; } } diff --git a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart index 274452468..07521040c 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid-wildcard-cases-with-enums + import 'package:flutter/material.dart'; import '../../../di.dart'; @@ -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, }; @@ -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, }; From a4d8d927285107eb89333a1f7a28eeecfe23ae4c Mon Sep 17 00:00:00 2001 From: Justin Enerio Date: Fri, 20 Dec 2024 13:52:57 +0800 Subject: [PATCH 2/6] upd error messages --- .../kyc_sharing/widgets/extensions.dart | 14 ++++++------- .../espressocash_app/lib/l10n/intl_en.arb | 20 ++++++++++++++++--- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart index 07521040c..a8c91254c 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart @@ -27,9 +27,9 @@ extension KycBuildContext on BuildContext { final message = switch (error) { KycInvalidCode() => context.l10n.invalidEmail, KycEmailError(:final error) => switch (error) { - EmailError.blocked => 'context.l10n.emailBlocked', - EmailError.bounced => 'context.l10n.emailBounced', - EmailError.spam => 'context.l10n.emailSpam', + EmailError.blocked => context.l10n.emailBlocked, + EmailError.bounced => context.l10n.emailBounced, + EmailError.spam => context.l10n.emailSpam, }, _ => context.l10n.failedToSendVerificationCode, }; @@ -58,11 +58,11 @@ extension KycBuildContext on BuildContext { final message = switch (error) { KycInvalidCode() => context.l10n.wrongVerificationCode, KycPhoneError(:final error) => switch (error) { - PhoneError.blocked => 'context.l10n.phoneBlocked', - PhoneError.fraudBlock => 'context.l10n.phoneFraudBlock', + PhoneError.blocked => context.l10n.phoneBlocked, + PhoneError.fraudBlock => context.l10n.phoneFraudBlock, PhoneError.tooManyAttempts => - 'context.l10n.phoneTooManyAttempts', - PhoneError.undeliverable => 'context.l10n.phoneUndeliverable', + context.l10n.phoneTooManyAttempts, + PhoneError.undeliverable => context.l10n.phoneUndeliverable, }, _ => context.l10n.failedToSendVerificationCode, }; diff --git a/packages/espressocash_app/lib/l10n/intl_en.arb b/packages/espressocash_app/lib/l10n/intl_en.arb index 51458fedc..dee79a637 100644 --- a/packages/espressocash_app/lib/l10n/intl_en.arb +++ b/packages/espressocash_app/lib/l10n/intl_en.arb @@ -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": {} +} \ No newline at end of file From 373d1a41a33bb41dc400bf5d3260a70dd92b9a56 Mon Sep 17 00:00:00 2001 From: Justin Enerio Date: Mon, 6 Jan 2025 15:06:19 +0800 Subject: [PATCH 3/6] upd --- .../kyc_sharing/screens/phone_confirmation_screen.dart | 10 +++++++--- .../lib/features/kyc_sharing/widgets/extensions.dart | 9 ++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart b/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart index b8f155b01..e2beb835c 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid-wildcard-cases-with-enums - import 'package:flutter/material.dart'; import '../../../di.dart'; @@ -53,7 +51,13 @@ class _PhoneConfirmationScreenState extends State { final message = switch (error) { KycInvalidCode() => context.l10n.wrongVerificationCode, - _ => context.l10n.tryAgainLater, + KycEmailError() || + KycPhoneError() || + KycInvalidToken() || + KycInvalidData() || + KycGenericError() || + KycInvalid() => + context.l10n.tryAgainLater }; showCpErrorSnackbar(context, message: message); diff --git a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart index a8c91254c..c3460a078 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid-wildcard-cases-with-enums - import 'package:flutter/material.dart'; import '../../../di.dart'; @@ -31,7 +29,12 @@ extension KycBuildContext on BuildContext { EmailError.bounced => context.l10n.emailBounced, EmailError.spam => context.l10n.emailSpam, }, - _ => context.l10n.failedToSendVerificationCode, + KycPhoneError() => throw UnimplementedError(), + KycInvalidToken() || + KycInvalidData() || + KycGenericError() || + KycInvalid() => + context.l10n.failedToSendVerificationCode }; showCpErrorSnackbar(context, message: message); From fed1922c3a33d83a13d3353465137fc39336961f Mon Sep 17 00:00:00 2001 From: Justin Enerio Date: Wed, 8 Jan 2025 21:04:06 +0800 Subject: [PATCH 4/6] upd --- .../screens/email_confirmation_screen.dart | 25 ++- .../screens/phone_confirmation_screen.dart | 29 ++- .../kyc_sharing/utils/kyc_exception.dart | 168 +++++++++--------- .../kyc_sharing/widgets/extensions.dart | 66 ++++--- .../espressocash_app/lib/l10n/intl_en.arb | 4 +- 5 files changed, 168 insertions(+), 124 deletions(-) diff --git a/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart b/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart index 3060291d3..834dd8ce3 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid-wildcard-cases-with-enums - import 'package:flutter/material.dart'; import '../../../di.dart'; @@ -45,9 +43,26 @@ class _EmailConfirmationScreenState extends State { } on KycException catch (error) { if (!mounted) return false; - final message = switch (error) { - KycInvalidCode() => context.l10n.wrongVerificationCode, - _ => context.l10n.tryAgainLater, + final message = switch (error.type) { + KycErrorType.invalidCode => context.l10n.wrongVerificationCode, + KycErrorType.invalidToken || + KycErrorType.invalidData || + KycErrorType.phoneBlocked || + KycErrorType.phoneFraudBlock || + KycErrorType.phoneTooManyAttempts || + KycErrorType.phoneUndeliverable || + KycErrorType.invalidPhone || + KycErrorType.emailBlocked || + KycErrorType.emailBounced || + KycErrorType.emailSpam || + KycErrorType.emailUndeliverable || + KycErrorType.invalidEmail || + KycErrorType.unverifiedContact || + KycErrorType.validationInProgress || + KycErrorType.smileIDJobNotCompleted || + KycErrorType.smileIDCannotUpload || + KycErrorType.generic => + context.l10n.tryAgainLater, }; showCpErrorSnackbar(context, message: message); diff --git a/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart b/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart index e2beb835c..920c3dadf 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart @@ -49,15 +49,26 @@ class _PhoneConfirmationScreenState extends State { } on KycException catch (error) { if (!mounted) return false; - final message = switch (error) { - KycInvalidCode() => context.l10n.wrongVerificationCode, - KycEmailError() || - KycPhoneError() || - KycInvalidToken() || - KycInvalidData() || - KycGenericError() || - KycInvalid() => - context.l10n.tryAgainLater + final message = switch (error.type) { + KycErrorType.invalidCode => context.l10n.wrongVerificationCode, + KycErrorType.invalidToken || + KycErrorType.invalidData || + KycErrorType.phoneBlocked || + KycErrorType.phoneFraudBlock || + KycErrorType.phoneTooManyAttempts || + KycErrorType.phoneUndeliverable || + KycErrorType.invalidPhone || + KycErrorType.emailBlocked || + KycErrorType.emailBounced || + KycErrorType.emailSpam || + KycErrorType.emailUndeliverable || + KycErrorType.invalidEmail || + KycErrorType.unverifiedContact || + KycErrorType.validationInProgress || + KycErrorType.smileIDJobNotCompleted || + KycErrorType.smileIDCannotUpload || + KycErrorType.generic => + context.l10n.tryAgainLater, }; showCpErrorSnackbar(context, message: message); diff --git a/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart b/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart index 9ba173d75..4c6666c1c 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart @@ -4,33 +4,42 @@ import '../../../utils/errors.dart'; part 'kyc_exception.freezed.dart'; -@freezed -sealed class KycException with _$KycException implements Exception { - // 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 KycErrorType { + // Auth + invalidToken, + invalidData, + invalidCode, + + // Phone + phoneBlocked, + phoneFraudBlock, + phoneTooManyAttempts, + phoneUndeliverable, + invalidPhone, + + // Email + emailBlocked, + emailBounced, + emailSpam, + emailUndeliverable, + invalidEmail, + + // Document + unverifiedContact, + validationInProgress, + smileIDJobNotCompleted, + smileIDCannotUpload, + + // Fallback + generic; } -enum EmailError { - blocked, - bounced, - spam, +@freezed +sealed class KycException with _$KycException implements Exception { + const factory KycException( + KycErrorType type, { + String? message, + }) = _KycException; } extension ErrorExt on Exception { @@ -38,72 +47,59 @@ extension ErrorExt on Exception { if (this is! DioException) { reportError(this, StackTrace.current); - return const KycException.genericError(); + return const KycException(KycErrorType.generic); } - final dioException = this as DioException; - final message = (dioException.response?.data - as Map?)?['message'] as String?; - final code = - (dioException.response?.data as Map?)?['code'] as int?; - + final message = (this as DioException).response?.data.toString(); 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') => - 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; - } + reportError(this, StackTrace.current); - // 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 const KycException(KycErrorType.generic); } - return exception; + return KycException( + switch (message) { + // Authentication/Validation errors + final s when s.contains('invalid token') => KycErrorType.invalidToken, + final s when s.contains('invalid data') => KycErrorType.invalidData, + final s when s.contains('invalid code') => KycErrorType.invalidCode, + + // Phone verification errors + final s when s.contains('invalid phone') => KycErrorType.invalidPhone, + final s when s.contains('phone number is blocked') => + KycErrorType.phoneBlocked, + final s when s.contains('phone number blocked due to fraud') => + KycErrorType.phoneFraudBlock, + final s when s.contains('too many verification attempts') => + KycErrorType.phoneTooManyAttempts, + final s when s.contains('phone number is undeliverable') => + KycErrorType.phoneUndeliverable, + + // Email verification errors + final s when s.contains('invalid email') => KycErrorType.invalidEmail, + final s when s.contains('email address is blocked') => + KycErrorType.emailBlocked, + final s when s.contains('email address has bounced') => + KycErrorType.emailBounced, + final s when s.contains('email blocked due to spam') => + KycErrorType.emailSpam, + final s when s.contains('email address is undeliverable') => + KycErrorType.emailUndeliverable, + + // Document validation errors + final s when s.contains('email and phone must be verified') => + KycErrorType.unverifiedContact, + final s when s.contains('validation already in progress') => + KycErrorType.validationInProgress, + final s when s.contains('smileID job not completed') => + KycErrorType.smileIDJobNotCompleted, + final s when s.contains('failed to upload') => + KycErrorType.smileIDCannotUpload, + + // Fallback + _ => KycErrorType.generic + }, + message: message, + ); } } diff --git a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart index c3460a078..790139b80 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart @@ -22,19 +22,27 @@ extension KycBuildContext on BuildContext { } on KycException catch (error) { if (!mounted) return false; - final message = switch (error) { - KycInvalidCode() => context.l10n.invalidEmail, - KycEmailError(:final error) => switch (error) { - EmailError.blocked => context.l10n.emailBlocked, - EmailError.bounced => context.l10n.emailBounced, - EmailError.spam => context.l10n.emailSpam, - }, - KycPhoneError() => throw UnimplementedError(), - KycInvalidToken() || - KycInvalidData() || - KycGenericError() || - KycInvalid() => - context.l10n.failedToSendVerificationCode + final message = switch (error.type) { + KycErrorType.invalidEmail => context.l10n.invalidEmail, + KycErrorType.emailBlocked => context.l10n.emailBlocked, + KycErrorType.emailBounced => context.l10n.emailBounced, + KycErrorType.emailSpam => context.l10n.emailSpam, + KycErrorType.emailUndeliverable => + context.l10n.emailUndeliverable, + KycErrorType.phoneBlocked || + KycErrorType.phoneFraudBlock || + KycErrorType.phoneTooManyAttempts || + KycErrorType.phoneUndeliverable || + KycErrorType.unverifiedContact || + KycErrorType.validationInProgress || + KycErrorType.smileIDJobNotCompleted || + KycErrorType.smileIDCannotUpload || + KycErrorType.invalidToken || + KycErrorType.invalidData || + KycErrorType.invalidCode || + KycErrorType.invalidPhone || + KycErrorType.generic => + context.l10n.failedToSendVerificationCode, }; showCpErrorSnackbar(context, message: message); @@ -58,16 +66,28 @@ extension KycBuildContext on BuildContext { } on KycException catch (error) { if (!mounted) return false; - final message = switch (error) { - 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, + final message = switch (error.type) { + KycErrorType.invalidPhone => context.l10n.invalidPhone, + KycErrorType.phoneBlocked => context.l10n.phoneBlocked, + KycErrorType.phoneFraudBlock => context.l10n.phoneFraudBlock, + KycErrorType.phoneTooManyAttempts => + context.l10n.phoneTooManyAttempts, + KycErrorType.phoneUndeliverable => + context.l10n.phoneUndeliverable, + KycErrorType.invalidToken || + KycErrorType.invalidData || + KycErrorType.emailBlocked || + KycErrorType.emailBounced || + KycErrorType.emailSpam || + KycErrorType.emailUndeliverable || + KycErrorType.unverifiedContact || + KycErrorType.validationInProgress || + KycErrorType.smileIDJobNotCompleted || + KycErrorType.smileIDCannotUpload || + KycErrorType.invalidEmail || + KycErrorType.invalidCode || + KycErrorType.generic => + context.l10n.failedToSendVerificationCode, }; showCpErrorSnackbar(context, message: message); diff --git a/packages/espressocash_app/lib/l10n/intl_en.arb b/packages/espressocash_app/lib/l10n/intl_en.arb index dee79a637..4334394b1 100644 --- a/packages/espressocash_app/lib/l10n/intl_en.arb +++ b/packages/espressocash_app/lib/l10n/intl_en.arb @@ -1212,12 +1212,14 @@ "@emailBounced": {}, "emailSpam": "This email address has been marked as spam", "@emailSpam": {}, + "emailUndeliverable": "Unable to send to this email address", + "@emailUndeliverable": {}, "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": "Unable to send to this phone number", "@phoneUndeliverable": {} } \ No newline at end of file From fd26f7bcedb05e1f5c40fd7985c5ccc8513103ef Mon Sep 17 00:00:00 2001 From: Justin Enerio Date: Mon, 13 Jan 2025 23:50:22 +0800 Subject: [PATCH 5/6] upd --- .../screens/email_confirmation_screen.dart | 23 +--- .../screens/phone_confirmation_screen.dart | 23 +--- .../kyc_sharing/utils/kyc_exception.dart | 111 ++++-------------- .../kyc_sharing/widgets/extensions.dart | 50 ++------ .../espressocash_app/lib/l10n/intl_en.arb | 16 +-- 5 files changed, 36 insertions(+), 187 deletions(-) diff --git a/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart b/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart index 834dd8ce3..ac56db2f4 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/screens/email_confirmation_screen.dart @@ -43,26 +43,9 @@ class _EmailConfirmationScreenState extends State { } on KycException catch (error) { if (!mounted) return false; - final message = switch (error.type) { - KycErrorType.invalidCode => context.l10n.wrongVerificationCode, - KycErrorType.invalidToken || - KycErrorType.invalidData || - KycErrorType.phoneBlocked || - KycErrorType.phoneFraudBlock || - KycErrorType.phoneTooManyAttempts || - KycErrorType.phoneUndeliverable || - KycErrorType.invalidPhone || - KycErrorType.emailBlocked || - KycErrorType.emailBounced || - KycErrorType.emailSpam || - KycErrorType.emailUndeliverable || - KycErrorType.invalidEmail || - KycErrorType.unverifiedContact || - KycErrorType.validationInProgress || - KycErrorType.smileIDJobNotCompleted || - KycErrorType.smileIDCannotUpload || - KycErrorType.generic => - context.l10n.tryAgainLater, + final message = switch (error) { + KycInvalidCode() => context.l10n.wrongVerificationCode, + _ => context.l10n.tryAgainLater, }; showCpErrorSnackbar(context, message: message); diff --git a/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart b/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart index 920c3dadf..2987fc6c8 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/screens/phone_confirmation_screen.dart @@ -49,26 +49,9 @@ class _PhoneConfirmationScreenState extends State { } on KycException catch (error) { if (!mounted) return false; - final message = switch (error.type) { - KycErrorType.invalidCode => context.l10n.wrongVerificationCode, - KycErrorType.invalidToken || - KycErrorType.invalidData || - KycErrorType.phoneBlocked || - KycErrorType.phoneFraudBlock || - KycErrorType.phoneTooManyAttempts || - KycErrorType.phoneUndeliverable || - KycErrorType.invalidPhone || - KycErrorType.emailBlocked || - KycErrorType.emailBounced || - KycErrorType.emailSpam || - KycErrorType.emailUndeliverable || - KycErrorType.invalidEmail || - KycErrorType.unverifiedContact || - KycErrorType.validationInProgress || - KycErrorType.smileIDJobNotCompleted || - KycErrorType.smileIDCannotUpload || - KycErrorType.generic => - context.l10n.tryAgainLater, + final message = switch (error) { + KycInvalidCode() => context.l10n.wrongVerificationCode, + _ => context.l10n.tryAgainLater, }; showCpErrorSnackbar(context, message: message); diff --git a/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart b/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart index 4c6666c1c..dd2b69310 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/utils/kyc_exception.dart @@ -1,105 +1,38 @@ import 'package:dio/dio.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import '../../../utils/errors.dart'; part 'kyc_exception.freezed.dart'; -enum KycErrorType { - // Auth - invalidToken, - invalidData, - invalidCode, - - // Phone - phoneBlocked, - phoneFraudBlock, - phoneTooManyAttempts, - phoneUndeliverable, - invalidPhone, - - // Email - emailBlocked, - emailBounced, - emailSpam, - emailUndeliverable, - invalidEmail, - - // Document - unverifiedContact, - validationInProgress, - smileIDJobNotCompleted, - smileIDCannotUpload, - - // Fallback - generic; -} - @freezed sealed class KycException with _$KycException implements Exception { - const factory KycException( - KycErrorType type, { - String? message, - }) = _KycException; + const factory KycException.invalidCode() = KycInvalidCode; + const factory KycException.invalidEmail() = KycInvalidEmail; + const factory KycException.invalidPhone() = KycInvalidPhone; + const factory KycException.invalidData() = KycInvalidData; + const factory KycException.invalidToken() = KycInvalidToken; + const factory KycException.genericError() = KycGenericError; + const factory KycException.phoneTooManyAttempts() = KycPhoneTooManyAttempts; } extension ErrorExt on Exception { KycException toKycException() { if (this is! DioException) { - reportError(this, StackTrace.current); - - return const KycException(KycErrorType.generic); + return const KycException.genericError(); } - final message = (this as DioException).response?.data.toString(); - if (message == null) { - reportError(this, StackTrace.current); - - return const KycException(KycErrorType.generic); - } - - return KycException( - switch (message) { - // Authentication/Validation errors - final s when s.contains('invalid token') => KycErrorType.invalidToken, - final s when s.contains('invalid data') => KycErrorType.invalidData, - final s when s.contains('invalid code') => KycErrorType.invalidCode, - - // Phone verification errors - final s when s.contains('invalid phone') => KycErrorType.invalidPhone, - final s when s.contains('phone number is blocked') => - KycErrorType.phoneBlocked, - final s when s.contains('phone number blocked due to fraud') => - KycErrorType.phoneFraudBlock, - final s when s.contains('too many verification attempts') => - KycErrorType.phoneTooManyAttempts, - final s when s.contains('phone number is undeliverable') => - KycErrorType.phoneUndeliverable, - - // Email verification errors - final s when s.contains('invalid email') => KycErrorType.invalidEmail, - final s when s.contains('email address is blocked') => - KycErrorType.emailBlocked, - final s when s.contains('email address has bounced') => - KycErrorType.emailBounced, - final s when s.contains('email blocked due to spam') => - KycErrorType.emailSpam, - final s when s.contains('email address is undeliverable') => - KycErrorType.emailUndeliverable, - - // Document validation errors - final s when s.contains('email and phone must be verified') => - KycErrorType.unverifiedContact, - final s when s.contains('validation already in progress') => - KycErrorType.validationInProgress, - final s when s.contains('smileID job not completed') => - KycErrorType.smileIDJobNotCompleted, - final s when s.contains('failed to upload') => - KycErrorType.smileIDCannotUpload, - - // Fallback - _ => KycErrorType.generic - }, - message: message, - ); + final dioException = this as DioException; + final message = (dioException.response?.data + as Map?)?['message'] as String?; + + 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(), + 'too many verification attempts' => + const KycException.phoneTooManyAttempts(), + _ => const KycException.genericError(), + }; } } diff --git a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart index 790139b80..00fe4c476 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart @@ -22,27 +22,9 @@ extension KycBuildContext on BuildContext { } on KycException catch (error) { if (!mounted) return false; - final message = switch (error.type) { - KycErrorType.invalidEmail => context.l10n.invalidEmail, - KycErrorType.emailBlocked => context.l10n.emailBlocked, - KycErrorType.emailBounced => context.l10n.emailBounced, - KycErrorType.emailSpam => context.l10n.emailSpam, - KycErrorType.emailUndeliverable => - context.l10n.emailUndeliverable, - KycErrorType.phoneBlocked || - KycErrorType.phoneFraudBlock || - KycErrorType.phoneTooManyAttempts || - KycErrorType.phoneUndeliverable || - KycErrorType.unverifiedContact || - KycErrorType.validationInProgress || - KycErrorType.smileIDJobNotCompleted || - KycErrorType.smileIDCannotUpload || - KycErrorType.invalidToken || - KycErrorType.invalidData || - KycErrorType.invalidCode || - KycErrorType.invalidPhone || - KycErrorType.generic => - context.l10n.failedToSendVerificationCode, + final message = switch (error) { + KycInvalidEmail() => context.l10n.invalidEmail, + _ => context.l10n.failedToSendVerificationCode, }; showCpErrorSnackbar(context, message: message); @@ -66,28 +48,10 @@ extension KycBuildContext on BuildContext { } on KycException catch (error) { if (!mounted) return false; - final message = switch (error.type) { - KycErrorType.invalidPhone => context.l10n.invalidPhone, - KycErrorType.phoneBlocked => context.l10n.phoneBlocked, - KycErrorType.phoneFraudBlock => context.l10n.phoneFraudBlock, - KycErrorType.phoneTooManyAttempts => - context.l10n.phoneTooManyAttempts, - KycErrorType.phoneUndeliverable => - context.l10n.phoneUndeliverable, - KycErrorType.invalidToken || - KycErrorType.invalidData || - KycErrorType.emailBlocked || - KycErrorType.emailBounced || - KycErrorType.emailSpam || - KycErrorType.emailUndeliverable || - KycErrorType.unverifiedContact || - KycErrorType.validationInProgress || - KycErrorType.smileIDJobNotCompleted || - KycErrorType.smileIDCannotUpload || - KycErrorType.invalidEmail || - KycErrorType.invalidCode || - KycErrorType.generic => - context.l10n.failedToSendVerificationCode, + final message = switch (error) { + KycInvalidPhone() => context.l10n.invalidPhone, + KycPhoneTooManyAttempts() => context.l10n.phoneTooManyAttempts, + _ => context.l10n.failedToSendVerificationCode, }; showCpErrorSnackbar(context, message: message); diff --git a/packages/espressocash_app/lib/l10n/intl_en.arb b/packages/espressocash_app/lib/l10n/intl_en.arb index 4334394b1..b56570c30 100644 --- a/packages/espressocash_app/lib/l10n/intl_en.arb +++ b/packages/espressocash_app/lib/l10n/intl_en.arb @@ -1206,20 +1206,6 @@ "@pendingKycDialogMessage": {}, "continueVerification": "Continue Verification", "@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": {}, - "emailUndeliverable": "Unable to send to this email address", - "@emailUndeliverable": {}, - "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 send to this phone number", - "@phoneUndeliverable": {} + "@phoneTooManyAttempts": {} } \ No newline at end of file From 94f85112073fbc5b215323e18adb2b96329787b7 Mon Sep 17 00:00:00 2001 From: Justin Enerio Date: Mon, 13 Jan 2025 23:53:15 +0800 Subject: [PATCH 6/6] upd --- .../features/kyc_sharing/widgets/extensions.dart | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart index 00fe4c476..1d8c5b3d7 100644 --- a/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart +++ b/packages/espressocash_app/lib/features/kyc_sharing/widgets/extensions.dart @@ -24,7 +24,13 @@ extension KycBuildContext on BuildContext { final message = switch (error) { KycInvalidEmail() => context.l10n.invalidEmail, - _ => context.l10n.failedToSendVerificationCode, + KycInvalidCode() || + KycInvalidData() || + KycInvalidToken() || + KycInvalidPhone() || + KycPhoneTooManyAttempts() || + KycGenericError() => + context.l10n.failedToSendVerificationCode, }; showCpErrorSnackbar(context, message: message); @@ -51,7 +57,12 @@ extension KycBuildContext on BuildContext { final message = switch (error) { KycInvalidPhone() => context.l10n.invalidPhone, KycPhoneTooManyAttempts() => context.l10n.phoneTooManyAttempts, - _ => context.l10n.failedToSendVerificationCode, + KycInvalidCode() || + KycInvalidEmail() || + KycInvalidData() || + KycInvalidToken() || + KycGenericError() => + context.l10n.failedToSendVerificationCode, }; showCpErrorSnackbar(context, message: message);