Skip to content

feat: optimize cant-do error handling#292

Merged
grunch merged 4 commits into
mainfrom
missing-cantdo
Sep 8, 2025
Merged

feat: optimize cant-do error handling#292
grunch merged 4 commits into
mainfrom
missing-cantdo

Conversation

@Catrya

@Catrya Catrya commented Sep 5, 2025

Copy link
Copy Markdown
Member
  • Replace inefficient if-else chain with Map lookup
  • Add missing cant-do error types
  • Fix duplicate notifications where users saw both specific errors and generic "order update" messages
  • Remove broken placeholders from outOfRangeFiatAmount across all languages

Summary by CodeRabbit

  • Bug Fixes

    • Prevents duplicate temporary notifications for “Can’t do” actions by ensuring they use dedicated handling and are not re-sent.
  • Localization

    • EN/ES/IT messages for user-creation failures now attribute to the service and suggest retrying.
    • “Out of range fiat amount” messages simplified across locales (min/max placeholders removed).
  • Refactor

    • Centralized mapping of “Can’t do” reasons to localized messages with fallback and warning for unknown codes.

  - Replace if-else chain with Map lookup for better performance
  - Add missing cant-do error types with proper localization
@coderabbitai

coderabbitai Bot commented Sep 5, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Centralizes cant-do notification messages with a new CantDoNotificationMapper, replaces ad-hoc cant-do branching in NotificationListenerWidget, prevents duplicate temporary cantDo notifications in AbstractMostroNotifier, switches outOfRangeFiatAmount to a parameterless localization getter, and updates EN/ES/IT ARB strings.

Changes

Cohort / File(s) Summary
Notifier event handling
lib/features/order/notfiers/abstract_mostro_notifier.dart
Guard default notification path: skip sendNotification for Action.cantDo in the default branch to avoid duplicate temporary notifications; added clarifying comment.
Mostro message detail
lib/features/trades/widgets/mostro_message_detail_widget.dart
Use parameterless outOfRangeFiatAmount localization getter for CantDoReason.outOfRangeFiatAmount instead of the previous parameterized call.
Localization strings (EN/ES/IT)
lib/l10n/intl_en.arb, lib/l10n/intl_es.arb, lib/l10n/intl_it.arb
Update cantCreateUser wording and remove min/max placeholders from outOfRangeFiatAmount, causing the localization API for outOfRangeFiatAmount to change from a function to a getter.
Notification mapping refactor
lib/shared/widgets/notification_listener_widget.dart
Add CantDoNotificationMapper with static String getMessage(BuildContext, String) and replace long ad-hoc cant-do reason checks with centralized lookup + logging fallback; retain existing customMessage and other action handling.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as App UI
  participant Notifier as AbstractMostroNotifier
  participant Listener as NotificationListenerWidget
  participant Mapper as CantDoNotificationMapper
  participant Local as Localization (S)

  UI->>Notifier: handleEvent(event)
  Notifier-->>Listener: dispatch notification payload
  alt payload.action == cantDo
    Listener->>Mapper: getMessage(context, cantDoReason)
    Mapper->>Local: lookup localized string
    Local-->>Mapper: localized cant-do message
    Mapper-->>Listener: message (or generic fallback)
    Listener-->>UI: show cant-do notification
  else payload.action != cantDo
    Listener->>Local: getLocalizedTitle(action)
    Local-->>Listener: title
    Listener-->>UI: show temporary notification
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • grunch

Poem

A twitch of whiskers, code aligned,
Mapped every "can't" so none repeat;
Strings trimmed simple, messages kind,
Notifications tidy, neat.
Hop, carrot, merge — the rabbits cheer! 🥕

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch missing-cantdo

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
lib/shared/widgets/notification_listener_widget.dart (3)

9-9: Prevent instantiation of static-only mapper.

Make the class non-instantiable.

-class CantDoNotificationMapper {
+class CantDoNotificationMapper {
+  CantDoNotificationMapper._();

11-27: Nit: avoid the null-bang on S.of(context) if not needed.

If the generated l10n API returns non-null, drop ! to satisfy lints. Apply across entries.

-    'pending_order_exists': (context) => S.of(context)!.pendingOrderExists,
+    'pending_order_exists': (context) => S.of(context).pendingOrderExists,

29-36: Log unknown cant-do reasons for observability.

Keep user-facing fallback, but log the unhandled reason to catch gaps.

-    // Fallback to generic cant-do message
-    return NotificationMessageMapper.getLocalizedTitle(context, mostro.Action.cantDo);
+    // Fallback to generic cant-do message
+    assert(() {
+      // Helps surface missing mappings in debug builds.
+      // ignore: avoid_print
+      print('[CantDoNotificationMapper] Unhandled cant-do reason: $cantDoReason');
+      return true;
+    }());
+    return NotificationMessageMapper.getLocalizedTitle(context, mostro.Action.cantDo);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bbbeb6f and ab7aba3.

📒 Files selected for processing (6)
  • lib/features/order/notfiers/abstract_mostro_notifier.dart (1 hunks)
  • lib/features/trades/widgets/mostro_message_detail_widget.dart (1 hunks)
  • lib/l10n/intl_en.arb (1 hunks)
  • lib/l10n/intl_es.arb (1 hunks)
  • lib/l10n/intl_it.arb (1 hunks)
  • lib/shared/widgets/notification_listener_widget.dart (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
lib/l10n/intl_{en,es,it}.arb

📄 CodeRabbit inference engine (CLAUDE.md)

Add new localization keys to all three ARB files (en, es, it)

Files:

  • lib/l10n/intl_en.arb
  • lib/l10n/intl_es.arb
  • lib/l10n/intl_it.arb
{lib/*.dart,lib/!(generated)/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart}: Use localized strings; replace hardcoded user-facing text with S.of(context).keyName
Prefer const constructors and const where possible
Use latest Flutter/Dart APIs (e.g., withValues() instead of deprecated withOpacity())

Files:

  • lib/shared/widgets/notification_listener_widget.dart
  • lib/features/trades/widgets/mostro_message_detail_widget.dart
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}: Check mounted before using BuildContext after await (async gaps)
Remove unused imports and dependencies

Files:

  • lib/shared/widgets/notification_listener_widget.dart
  • lib/features/trades/widgets/mostro_message_detail_widget.dart
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

All code comments, variable names, and function names must be in English

Files:

  • lib/shared/widgets/notification_listener_widget.dart
  • lib/features/trades/widgets/mostro_message_detail_widget.dart
  • lib/features/order/notfiers/abstract_mostro_notifier.dart
🧠 Learnings (4)
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Applies to lib/l10n/intl_{en,es,it}.arb : Add new localization keys to all three ARB files (en, es, it)

Applied to files:

  • lib/l10n/intl_en.arb
  • lib/l10n/intl_es.arb
📚 Learning: 2025-07-08T05:40:47.527Z
Learnt from: chebizarro
PR: MostroP2P/mobile#127
File: lib/data/models/cant_do.dart:10-27
Timestamp: 2025-07-08T05:40:47.527Z
Learning: In the CantDo model parsing in lib/data/models/cant_do.dart, the inconsistent key naming between 'cant_do' (top-level) and 'cant-do' (nested) is required by the protocol specification and should not be changed as it would break message parsing compatibility.

Applied to files:

  • lib/shared/widgets/notification_listener_widget.dart
📚 Learning: 2025-07-20T23:33:17.689Z
Learnt from: Catrya
PR: MostroP2P/mobile#215
File: lib/features/order/notfiers/order_notifier.dart:0-0
Timestamp: 2025-07-20T23:33:17.689Z
Learning: In AbstractMostroNotifier, the handleEvent method is synchronous and returns void, not Future<void>. Do not suggest adding await to super.handleEvent() calls as this would cause compilation errors.

Applied to files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
📚 Learning: 2025-06-26T15:03:23.529Z
Learnt from: chebizarro
PR: MostroP2P/mobile#127
File: lib/features/order/notfiers/abstract_mostro_notifier.dart:45-54
Timestamp: 2025-06-26T15:03:23.529Z
Learning: In AbstractMostroNotifier, state updates occur for all messages regardless of timestamp to hydrate the OrderNotifier from MostroStorage during sync, while handleEvent is only called for recent messages (within 60 seconds) to prevent re-triggering side effects like notifications and navigation for previously handled messages. This design prevents displaying stale notifications when the app is reopened or brought to the foreground.

Applied to files:

  • lib/features/order/notfiers/abstract_mostro_notifier.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (9)
lib/features/order/notfiers/abstract_mostro_notifier.dart (1)

333-336: Good guard to stop duplicate cantDo notifications.

Skipping cantDo in the default branch prevents the extra generic “order update” temp notification. Matches the PR goal to eliminate dupes.

lib/features/trades/widgets/mostro_message_detail_widget.dart (1)

253-253: Replace remaining parameterized call to outOfRangeFiatAmount
In lib/data/models/enums/cant_do_reason.dart:18, update the invocation

outOfRangeFiatAmount('out_of_range_fiat_amount')

to the parameterless getter to match the ARB/API change.

⛔ Skipped due to learnings
Learnt from: chebizarro
PR: MostroP2P/mobile#127
File: lib/data/models/cant_do.dart:10-27
Timestamp: 2025-07-08T05:40:47.527Z
Learning: In the CantDo model parsing in lib/data/models/cant_do.dart, the inconsistent key naming between 'cant_do' (top-level) and 'cant-do' (nested) is required by the protocol specification and should not be changed as it would break message parsing compatibility.
lib/l10n/intl_en.arb (2)

136-136: Copy update OK.

Reworded cantCreateUser reads naturally and matches other locales.


139-139: Placeholders removed as intended.

outOfRangeFiatAmount now generic; consistent with code changes.

lib/l10n/intl_es.arb (1)

139-139: Placeholders removed as intended.

outOfRangeFiatAmount now generic; consistent with code changes.

lib/l10n/intl_it.arb (2)

136-136: Copy update OK.

Reworded cantCreateUser matches intent and tone.


139-139: Placeholders removed as intended.

outOfRangeFiatAmount now generic; consistent with code changes.

lib/shared/widgets/notification_listener_widget.dart (2)

9-27: Great call: centralized cant-do mapping.

This removes branching, keeps all messages localized, and simplifies maintenance. Looks correct.


21-22: Good alignment with updated i18n API.

Using the parameterless outOfRangeFiatAmount getter matches the ARB/l10n change.

Comment thread lib/l10n/intl_es.arb Outdated
Comment thread lib/shared/widgets/notification_listener_widget.dart Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
lib/l10n/intl_es.arb (1)

136-136: Brand capitalization fixed — looks good.

“Mostro” is correctly capitalized now and the phrasing reads naturally.

lib/shared/widgets/notification_listener_widget.dart (1)

74-81: Guard next.values to avoid runtime exceptions on malformed payloads.

If values is null or not a Map, current code will throw. Safely check before indexing.

-          if (next.action == mostro.Action.cantDo) {
-            final reason = next.values['action'];
+          if (next.action == mostro.Action.cantDo) {
+            final rawValues = next.values;
+            final reason = rawValues is Map ? rawValues['action'] : null;
             if (reason is String && reason.isNotEmpty) {
               message = CantDoNotificationMapper.getMessage(context, reason);
             } else {
               // Fallback if the payload is malformed or type changes
               message = NotificationMessageMapper.getLocalizedTitle(context, mostro.Action.cantDo);
             }
           } else {
🧹 Nitpick comments (2)
lib/shared/widgets/notification_listener_widget.dart (2)

10-30: Good centralization; add remaining cant-do mappings for full coverage.

You already cover most reasons; include the rest so we don’t fall back to generic when we have specific strings.

   static final _messageMap = <String, String Function(BuildContext)>{
@@
     'invalid_order_status': (context) => S.of(context)!.invalidOrderStatus,
+    'invalid_payment_request': (context) => S.of(context)!.invalidPaymentRequest,
+    'invalid_text_message': (context) => S.of(context)!.invalidTextMessage,
+    'invalid_parameters': (context) => S.of(context)!.invalidParameters,
+    'is_not_your_dispute': (context) => S.of(context)!.isNotYourDispute,
+    'dispute_creation_error': (context) => S.of(context)!.disputeCreationError,
+    'not_found': (context) => S.of(context)!.notFound,
+    'invalid_dispute_status': (context) => S.of(context)!.invalidDisputeStatus,
+    'invalid_action': (context) => S.of(context)!.invalidAction,
   };

32-42: Fallback is correct; consider a tiny unit test.

Add a test asserting a known reason returns the specific message and an unknown reason hits the generic fallback.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ab7aba3 and deb63ac.

📒 Files selected for processing (2)
  • lib/l10n/intl_es.arb (1 hunks)
  • lib/shared/widgets/notification_listener_widget.dart (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
lib/l10n/intl_{en,es,it}.arb

📄 CodeRabbit inference engine (CLAUDE.md)

Add new localization keys to all three ARB files (en, es, it)

Files:

  • lib/l10n/intl_es.arb
{lib/*.dart,lib/!(generated)/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart}: Use localized strings; replace hardcoded user-facing text with S.of(context).keyName
Prefer const constructors and const where possible
Use latest Flutter/Dart APIs (e.g., withValues() instead of deprecated withOpacity())

Files:

  • lib/shared/widgets/notification_listener_widget.dart
{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}: Check mounted before using BuildContext after await (async gaps)
Remove unused imports and dependencies

Files:

  • lib/shared/widgets/notification_listener_widget.dart
**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

All code comments, variable names, and function names must be in English

Files:

  • lib/shared/widgets/notification_listener_widget.dart
🧠 Learnings (3)
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Applies to lib/l10n/intl_{en,es,it}.arb : Add new localization keys to all three ARB files (en, es, it)

Applied to files:

  • lib/l10n/intl_es.arb
📚 Learning: 2025-07-08T05:40:47.527Z
Learnt from: chebizarro
PR: MostroP2P/mobile#127
File: lib/data/models/cant_do.dart:10-27
Timestamp: 2025-07-08T05:40:47.527Z
Learning: In the CantDo model parsing in lib/data/models/cant_do.dart, the inconsistent key naming between 'cant_do' (top-level) and 'cant-do' (nested) is required by the protocol specification and should not be changed as it would break message parsing compatibility.

Applied to files:

  • lib/shared/widgets/notification_listener_widget.dart
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Use Riverpod for state management with Notifiers encapsulating business logic; access data only through repositories

Applied to files:

  • lib/shared/widgets/notification_listener_widget.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
lib/l10n/intl_es.arb (1)

139-139: Resolved: locale consistency and call sites verified
EN and IT ARB entries for outOfRangeFiatAmount are now parameterless and no Dart call sites pass arguments.

lib/shared/widgets/notification_listener_widget.dart (1)

3-3: Logger import makes sense.

Used for unknown cant-do reasons; fine to keep.

@grunch grunch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@grunch grunch merged commit 0631cb0 into main Sep 8, 2025
2 checks passed
@grunch grunch deleted the missing-cantdo branch September 8, 2025 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants