fix: Show success message after feedback submission#3609
fix: Show success message after feedback submission#3609
Conversation
Display a success screen with successMessageText after feedback is submitted. The form is replaced with a checkmark icon and success message that auto-dismisses after 5 seconds or on tap. Adds `successColor` and `onSubmitSuccess` callback to `SentryFeedbackOptions`.
Android Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| cfca825 | 417.36 ms | 393.37 ms | -23.99 ms |
| 51520fc | 351.89 ms | 349.79 ms | -2.10 ms |
| 75284dc | 512.39 ms | 530.87 ms | 18.48 ms |
| a909995 | 383.55 ms | 370.78 ms | -12.77 ms |
| f761369 | 462.73 ms | 563.80 ms | 101.06 ms |
| 575ebaa | 478.00 ms | 585.76 ms | 107.76 ms |
| a5b28db | 383.85 ms | 387.65 ms | 3.80 ms |
| e5b87f8 | 371.22 ms | 377.22 ms | 6.00 ms |
| c8596a6 | 474.00 ms | 492.96 ms | 18.96 ms |
| 79f6b41 | 469.66 ms | 525.90 ms | 56.24 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| cfca825 | 14.09 MiB | 15.28 MiB | 1.19 MiB |
| 51520fc | 13.93 MiB | 15.18 MiB | 1.25 MiB |
| 75284dc | 13.93 MiB | 14.93 MiB | 1.00 MiB |
| a909995 | 14.09 MiB | 15.28 MiB | 1.19 MiB |
| f761369 | 6.54 MiB | 7.70 MiB | 1.16 MiB |
| 575ebaa | 6.54 MiB | 7.69 MiB | 1.15 MiB |
| a5b28db | 13.93 MiB | 15.18 MiB | 1.25 MiB |
| e5b87f8 | 13.93 MiB | 15.18 MiB | 1.25 MiB |
| c8596a6 | 6.54 MiB | 7.53 MiB | 1015.27 KiB |
| 79f6b41 | 6.54 MiB | 7.69 MiB | 1.15 MiB |
iOS Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 7cfbbd6 | 1270.63 ms | 1285.36 ms | 14.72 ms |
| e2d675d | 1238.48 ms | 1242.76 ms | 4.28 ms |
| e0c8591 | 1259.85 ms | 1257.31 ms | -2.54 ms |
| 1ce780b | 1252.49 ms | 1256.17 ms | 3.68 ms |
| d0aa4b6 | 1268.23 ms | 1268.39 ms | 0.15 ms |
| 3801d52 | 1267.76 ms | 1266.10 ms | -1.65 ms |
| c97f488 | 1247.40 ms | 1252.13 ms | 4.73 ms |
| fd88186 | 1255.06 ms | 1252.76 ms | -2.30 ms |
| aeb02f2 | 1244.29 ms | 1256.55 ms | 12.26 ms |
| c26ed0a | 1244.11 ms | 1263.85 ms | 19.75 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 7cfbbd6 | 7.86 MiB | 9.44 MiB | 1.58 MiB |
| e2d675d | 7.86 MiB | 9.44 MiB | 1.58 MiB |
| e0c8591 | 5.53 MiB | 5.96 MiB | 444.86 KiB |
| 1ce780b | 5.66 MiB | 6.10 MiB | 451.58 KiB |
| d0aa4b6 | 5.53 MiB | 6.02 MiB | 502.04 KiB |
| 3801d52 | 5.73 MiB | 6.17 MiB | 455.54 KiB |
| c97f488 | 5.73 MiB | 6.17 MiB | 455.48 KiB |
| fd88186 | 5.53 MiB | 6.00 MiB | 479.94 KiB |
| aeb02f2 | 7.86 MiB | 9.44 MiB | 1.58 MiB |
| c26ed0a | 5.53 MiB | 5.97 MiB | 453.76 KiB |
Sentry Build Distribution
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3609 +/- ##
==========================================
+ Coverage 86.83% 91.83% +4.99%
==========================================
Files 320 102 -218
Lines 10789 3502 -7287
==========================================
- Hits 9369 3216 -6153
+ Misses 1420 286 -1134
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
| if (mounted && _submitted) { | ||
| _dismiss(pendingAssociatedEventId: false); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Success message shown even when feedback capture fails
Medium Severity
The _submit method shows the success UI and invokes onSubmitSuccess without checking whether _captureFeedback actually succeeded. captureFeedback on the hub returns SentryId.empty() when the instance is disabled or when capture throws an exception. The established SDK pattern (visible in example_web/web/main.dart) is to check sentryId != SentryId.empty() before treating a capture as successful. Without this guard, users see "Thank you for your report!" and the onSubmitSuccess callback fires even when their feedback was silently dropped.
There was a problem hiding this comment.
The problem is, that we effectively do not get negative. We send an envelope to JS/Android/iOS downstream SDK. The modal is closed in any case.
| if (!_formKey.currentState!.validate()) { | ||
| return; | ||
| } | ||
|
|
||
| final feedback = SentryFeedback( | ||
| message: _messageController.text, | ||
| contactEmail: _emailController.text, | ||
| name: _nameController.text, | ||
| associatedEventId: widget.associatedEventId, | ||
| ); |
There was a problem hiding this comment.
Bug: The _submit() method lacks a guard against concurrent calls, allowing multiple submissions if the user taps the submit button quickly before the async operation completes.
Severity: MEDIUM
Suggested Fix
Introduce a boolean flag like _isSubmitting to guard the _submit method. Set it to true at the beginning of the method and false after the submission completes. Check this flag at the start of the method and return early if a submission is already in progress.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/flutter/lib/src/feedback/sentry_feedback_widget.dart#L423-L432
Potential issue: The `_submit()` method is an `async` function that can be invoked
multiple times before the first call completes, creating a race condition. If a user
taps the submit button twice in quick succession, `_captureFeedback()` will be called
twice, resulting in duplicate feedback reports being sent. Additionally, when the second
submission completes, it creates a new `Timer` and assigns it to `_successTimer`,
overwriting the reference to the first timer without cancelling it. This orphans the
first timer, causing a resource leak, and leads to the `onSubmitSuccess` callback being
invoked multiple times.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| } | ||
| }); | ||
| } | ||
|
|
There was a problem hiding this comment.
Timer not cancelled in _dismiss risks double navigation
Low Severity
_dismiss does not cancel _successTimer. The timer is only cancelled in dispose(). If a user taps the success screen (or close button) to dismiss very close to the 5-second auto-dismiss deadline, both the user action and the timer callback can call _dismiss, resulting in Navigator.maybePop being invoked twice during the same pop transition. Cancelling _successTimer at the start of _dismiss would prevent this race.
Additional Locations (1)
Triggered by project rule: PR Review Guidelines for Cursor Bot (Root)
buenaflor
left a comment
There was a problem hiding this comment.
as discussed let's do that but let's make the out of the box success widget not the whole screen, please look into what's idiomatic for Flutter


📜 Description
Display a success screen with successMessageText after feedback is submitted. The form is replaced with a checkmark icon and success message that auto-dismisses after 5 seconds or on tap. Adds
successColorandonSubmitSuccesscallback toSentryFeedbackOptions.💡 Motivation and Context
Closes #3583
💚 How did you test it?
📝 Checklist
sendDefaultPiiis enabled