-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/support form #69 #72
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
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the 📝 Walkthrough📝 Walkthrough📝 Walkthrough📝 WalkthroughWalkthroughThis pull request introduces a new support feature in the application, which includes the implementation of a Changes
Possibly related PRs
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🧹 Outside diff range and nitpick comments (7)
lib/features/support/presentation/widgets/ticket_form.dart (2)
17-33: Refactor to reduce code duplication in state listenersIn the
listenerfunction, the handling forSupportSuccessandSupportCachedstates is similar. Consider refactoring to reduce code duplication by handling these states together.Here's how you can refactor the code:
listener: (BuildContext context, SupportState state) { if (state is SupportSuccess || state is SupportCached) { + final String message = state is SupportSuccess + ? 'Ticket submitted successfully' + : state.message; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Ticket submitted successfully')), + SnackBar(content: Text(message)), ); Navigator.pop(context); } else if (state is SupportFailure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Failed to submit ticket: ${state.error}')), ); } },
38-76: Prevent overflow when keyboard appears by wrapping content in aSingleChildScrollViewTo avoid overflow issues when the keyboard appears, especially on smaller screens, wrap the form content in a
SingleChildScrollView.Apply this change:
return Padding( padding: const EdgeInsets.all(16.0), - child: Column( + child: SingleChildScrollView( + child: Column( children: <Widget>[ // ... existing widgets ... ], + ), + ), );lib/features/support/presentation/screens/support_screen.dart (2)
8-39: Add rotation handling to modal bottom sheetThe modal bottom sheet might not handle device rotation gracefully. Consider adding
useRootNavigator: trueand handling orientation changes.Apply this diff:
showModalBottomSheet<void>( context: context, isScrollControlled: true, + useRootNavigator: true, builder: (BuildContext context) {
76-159: Enhance accessibility supportAdd semantic labels and improve accessibility for support categories.
Apply this pattern to each ListTile:
ListTile( leading: const Icon(Icons.shopping_cart), title: const Text('Order Management'), trailing: const Icon(Icons.chevron_right), + semanticLabel: 'Order Management support options',lib/injection_container.dart (1)
222-230: Consider implementing complete feature architectureThe support feature setup is missing important architectural layers compared to other features:
- Repository layer for data management
- Use cases for business logic
- Data sources for local/remote data handling
This could make the feature harder to test and maintain.
Consider implementing these layers following the pattern used in other features like the profile feature. Example structure:
// Repository abstract class SupportRepository { Future<void> submitTicket(SupportTicket ticket); Future<List<SupportTicket>> getCachedTickets(); } // Use cases class SubmitTicketUseCase { final SupportRepository repository; Future<void> call(SupportTicket ticket) => repository.submitTicket(ticket); } // Data sources abstract class SupportRemoteDataSource { Future<void> submitTicket(SupportTicket ticket); }lib/features/profile/presentation/screens/profile_screen.dart (2)
122-131: Add error handling for navigationWhile the help button implementation is clean, consider adding error handling for navigation failures and a loading state during transition.
ElevatedButton( onPressed: () { - Navigator.pushNamed(context, '/support'); + try { + setState(() => _isNavigating = true); + Navigator.pushNamed(context, '/support').catchError((error) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Unable to access support screen')), + ); + }).whenComplete(() { + if (mounted) setState(() => _isNavigating = false); + }); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Navigation error occurred')), + ); + } }, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), textStyle: const TextStyle(fontSize: 18), ), - child: const Text('Need help?'), + child: _isNavigating + ? const CircularProgressIndicator() + : const Text('Need help?'), ),
Line range hint
155-194: Refactor save profile logic to avoid code duplicationThe profile saving logic is duplicated between the onPressed handler and _saveProfile method. Consider extracting the profile creation logic to a separate method.
+ Future<UserProfile?> _createUpdatedProfile() async { + final String? userId = FirebaseAuth.instance.currentUser?.uid; + if (userId == null) return null; + + return UserProfile( + userId: userId, + name: _nameController.text, + surname: _surnameController.text, + citizenId: _citizenIdController.text, + email: _emailController.text, + phone: _phoneController.text, + birthDate: DateFormat('MM/dd/yyyy').parse(_birthDateController.text), + favoriteCuisine: _favoriteCuisine ?? CuisineType.other, + dietType: _dietType ?? DietType.none, + ); + } ElevatedButton( - onPressed: () async { - final String? userId = FirebaseAuth.instance.currentUser?.uid; - if (userId != null) { - final UserProfile updatedProfile = UserProfile(...) - final InternetConnectionBloc internetConnectionBloc = ... + onPressed: () async { + final profile = await _createUpdatedProfile(); + if (profile != null) { + await _saveProfile(profile); + } }, child: const Text('Save'), ),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (9)
lib/app.dart(2 hunks)lib/features/profile/presentation/screens/profile_screen.dart(3 hunks)lib/features/support/presentation/bloc/support_bloc.dart(1 hunks)lib/features/support/presentation/bloc/support_event.dart(1 hunks)lib/features/support/presentation/bloc/support_state.dart(1 hunks)lib/features/support/presentation/screens/support_screen.dart(1 hunks)lib/features/support/presentation/widgets/ticket_form.dart(1 hunks)lib/injection_container.dart(3 hunks)lib/route_generator.dart(2 hunks)
🔇 Additional comments (12)
lib/features/support/presentation/bloc/support_event.dart (3)
3-8: Base event class is appropriately defined
The SupportEvent class correctly extends Equatable and provides an empty props list.
10-24: SubmitTicketEvent class is well-defined
The class properly extends SupportEvent, includes the required fields, and overrides props correctly.
26-26: RetryCachedTicketsEvent is correctly defined
An event to trigger the retry of cached tickets.
lib/features/support/presentation/bloc/support_state.dart (3)
3-8: Base state class correctly defined
The SupportState class properly extends Equatable and provides an empty props list.
16-22: SupportFailure state properly handles error information
The SupportFailure class includes an error field and overrides props accordingly.
24-31: SupportCached state correctly defined with message
The SupportCached class includes a message field and overrides props.
lib/route_generator.dart (3)
5-7: Imports added appropriately
The import statements for ProfileScreen and SupportScreen are correctly added.
15-16: Route constants defined correctly
The route constants supportScreen and profileScreen are appropriately added.
39-42: New routes handled correctly in generateRoute
The supportScreen and profileScreen routes are correctly added to the generateRoute method.
lib/app.dart (2)
72-72: LGTM: SupportBloc integration looks good
The SupportBloc is properly integrated into the MultiBlocProvider.
69-72:
Remove duplicate ProfileBloc provider
There are two identical ProfileBloc providers which could cause unexpected behavior with state management.
Apply this diff to fix the issue:
BlocProvider<ProfileBloc>(
create: (_) => serviceLocator<ProfileBloc>(),
),
- BlocProvider<ProfileBloc>(
- create: (_) => serviceLocator<ProfileBloc>(),
- ),
BlocProvider<SupportBloc>(create: (_) => serviceLocator<SupportBloc>()),Likely invalid or redundant comment.
lib/features/profile/presentation/screens/profile_screen.dart (1)
122-124: Verify route and bloc registration
Ensure that the support route and required blocs are properly registered.
✅ Verification successful
Route and bloc setup verified successfully
The verification confirms:
- Support route is properly registered in
lib/route_generator.dart - SupportBloc is correctly provided in the app's widget tree via
BlocProvider - Support screen exists at the expected location
lib/features/support/presentation/screens/support_screen.dart
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check route registration
echo "Checking route registration..."
rg -A 5 "'/support'" lib/route_generator.dart
# Check bloc provider setup
echo "Checking bloc provider setup..."
rg -A 5 "SupportBloc" lib/app.dart
# Verify support screen exists
echo "Verifying support screen..."
fd -e dart -p "support_screen.dart$"
Length of output: 862
| for (final String ticket in cachedTickets) { | ||
| final Map<String, dynamic> ticketData = jsonDecode(ticket); | ||
| try { | ||
| await firestore.collection('support_tickets').add(<String, dynamic>{ | ||
| 'category': ticketData['category'], | ||
| 'subOption': ticketData['subOption'], | ||
| 'reason': ticketData['reason'], | ||
| 'description': ticketData['description'], | ||
| 'timestamp': FieldValue.serverTimestamp(), | ||
| }); | ||
| } catch (e) { | ||
| emit(SupportFailure(error: e.toString())); | ||
| return; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Ensure all cached tickets are retried even if some submissions fail
Currently, if submitting a cached ticket fails, the method emits SupportFailure and returns, which stops the submission of any remaining cached tickets. It's better to attempt to submit all cached tickets, even if some fail, and handle failures accordingly.
Here's how you can modify the code:
+ final List<String> failedTickets = [];
for (final String ticket in cachedTickets) {
final Map<String, dynamic> ticketData = jsonDecode(ticket);
try {
await firestore.collection('support_tickets').add(<String, dynamic>{
'category': ticketData['category'],
'subOption': ticketData['subOption'],
'reason': ticketData['reason'],
'description': ticketData['description'],
'timestamp': FieldValue.serverTimestamp(),
});
} catch (e) {
+ failedTickets.add(ticket);
}
}
- emit(SupportFailure(error: e.toString()));
- return;
+ if (failedTickets.isNotEmpty) {
+ await prefs.setStringList('cachedTickets', failedTickets);
+ emit(SupportFailure(error: 'Some tickets failed to submit.'));
+ } else {
+ await prefs.remove('cachedTickets');
+ emit(SupportSuccess());
+ }Committable suggestion skipped: line range outside the PR's diff.
| internetConnectionBloc.stream.listen((InternetConnectionState state) { | ||
| if (state is ConnectedInternet) { | ||
| add(RetryCachedTicketsEvent()); | ||
| } | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Manage the StreamSubscription to prevent memory leaks
Currently, the subscription to internetConnectionBloc.stream is not being canceled when the SupportBloc is closed, which could lead to memory leaks. To prevent this, store the subscription and cancel it in the close method.
Here's how you can modify the code:
+ late final StreamSubscription<InternetConnectionState> _internetConnectionSubscription;
SupportBloc({required this.firestore, required this.internetConnectionBloc})
: super(SupportInitial()) {
- internetConnectionBloc.stream.listen((InternetConnectionState state) {
+ _internetConnectionSubscription = internetConnectionBloc.stream.listen((InternetConnectionState state) {
if (state is ConnectedInternet) {
add(RetryCachedTicketsEvent());
}
});
}
+ @override
+ Future<void> close() {
+ _internetConnectionSubscription.cancel();
+ return super.close();
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| internetConnectionBloc.stream.listen((InternetConnectionState state) { | |
| if (state is ConnectedInternet) { | |
| add(RetryCachedTicketsEvent()); | |
| } | |
| }); | |
| } | |
| late final StreamSubscription<InternetConnectionState> _internetConnectionSubscription; | |
| SupportBloc({required this.firestore, required this.internetConnectionBloc}) | |
| : super(SupportInitial()) { | |
| _internetConnectionSubscription = internetConnectionBloc.stream.listen((InternetConnectionState state) { | |
| if (state is ConnectedInternet) { | |
| add(RetryCachedTicketsEvent()); | |
| } | |
| }); | |
| } | |
| @override | |
| Future<void> close() { | |
| _internetConnectionSubscription.cancel(); | |
| return super.close(); | |
| } |
| class TicketForm extends StatelessWidget { | ||
| TicketForm({super.key, required this.category, required this.subOption}); | ||
| final String category; | ||
| final String subOption; | ||
|
|
||
| final TextEditingController reasonController = TextEditingController(); | ||
| final TextEditingController descriptionController = TextEditingController(); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Convert TicketForm to a StatefulWidget to manage controllers
Currently, TicketForm is a StatelessWidget but holds TextEditingController instances. Controllers are mutable and should be disposed to prevent memory leaks. Therefore, TicketForm should be converted to a StatefulWidget to properly manage the controllers and dispose of them in the dispose method.
Here's how you can modify the code:
- class TicketForm extends StatelessWidget {
+ class TicketForm extends StatefulWidget {
+ const TicketForm({super.key, required this.category, required this.subOption});
final String category;
final String subOption;
+ @override
+ _TicketFormState createState() => _TicketFormState();
+ }
+ class _TicketFormState extends State<TicketForm> {
+ late final TextEditingController reasonController;
+ late final TextEditingController descriptionController;
+ @override
+ void initState() {
+ super.initState();
+ reasonController = TextEditingController();
+ descriptionController = TextEditingController();
+ }
+ @override
+ void dispose() {
+ reasonController.dispose();
+ descriptionController.dispose();
+ super.dispose();
+ }
@override
Widget build(BuildContext context) {
// ...existing build method...
}
+ }Committable suggestion skipped: line range outside the PR's diff.
| : () { | ||
| context.read<SupportBloc>().add( | ||
| SubmitTicketEvent( | ||
| category: category, | ||
| subOption: subOption, | ||
| reason: reasonController.text, | ||
| description: descriptionController.text, | ||
| ), | ||
| ); | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add input validation before submitting the ticket
Currently, the form does not validate user input before submitting the ticket. To enhance user experience and prevent empty submissions, validate that the reason and description fields are not empty.
Here's how you can implement basic validation:
onPressed: state is SupportLoading
? null
: () {
+ if (reasonController.text.isEmpty || descriptionController.text.isEmpty) {
+ ScaffoldMessenger.of(context).showSnackBar(
+ const SnackBar(content: Text('Please fill in all fields')),
+ );
+ return;
+ }
context.read<SupportBloc>().add(
SubmitTicketEvent(
category: widget.category,
subOption: widget.subOption,
reason: reasonController.text,
description: descriptionController.text,
),
);
},Committable suggestion skipped: line range outside the PR's diff.
| ListTile( | ||
| leading: const Icon(Icons.shopping_cart), | ||
| title: const Text('Order Management'), | ||
| trailing: const Icon(Icons.chevron_right), | ||
| onTap: () { | ||
| _showOptions(context, 'Order Management', <String>[ | ||
| 'Track Order', | ||
| 'Cancel Order', | ||
| 'Return Order', | ||
| 'Order History', | ||
| ]); | ||
| }, | ||
| ), | ||
| const Divider(), | ||
| ListTile( | ||
| leading: const Icon(Icons.payment), | ||
| title: const Text('Payment Management'), | ||
| trailing: const Icon(Icons.chevron_right), | ||
| onTap: () { | ||
| _showOptions(context, 'Payment Management', <String>[ | ||
| 'Payment Methods', | ||
| 'Refund Status', | ||
| 'Payment Issues', | ||
| 'Billing History', | ||
| ]); | ||
| }, | ||
| ), | ||
| const Divider(), | ||
| ListTile( | ||
| leading: const Icon(Icons.account_circle), | ||
| title: const Text('Account and Profile Management'), | ||
| trailing: const Icon(Icons.chevron_right), | ||
| onTap: () { | ||
| _showOptions(context, 'Account and Profile Management', <String>[ | ||
| 'Update Profile', | ||
| 'Change Password', | ||
| 'Privacy Settings', | ||
| 'Delete Account', | ||
| ]); | ||
| }, | ||
| ), | ||
| const Divider(), | ||
| ListTile( | ||
| leading: const Icon(Icons.info), | ||
| title: const Text('About EcoBites'), | ||
| trailing: const Icon(Icons.chevron_right), | ||
| onTap: () { | ||
| _showOptions(context, 'About EcoBites', <String>[ | ||
| 'Company Information', | ||
| 'Terms of Service', | ||
| 'Privacy Policy', | ||
| 'Contact Us', | ||
| ]); | ||
| }, | ||
| ), | ||
| const Divider(), | ||
| ListTile( | ||
| leading: const Icon(Icons.security), | ||
| title: const Text('Security'), | ||
| trailing: const Icon(Icons.chevron_right), | ||
| onTap: () { | ||
| _showOptions(context, 'Security', <String>[ | ||
| 'Report a Security Issue', | ||
| 'Account Security Tips', | ||
| 'Two-Factor Authentication', | ||
| 'Security Updates', | ||
| ]); | ||
| }, | ||
| ), | ||
| const Divider(), | ||
| ListTile( | ||
| leading: const Icon(Icons.history), | ||
| title: const Text('Message History'), | ||
| trailing: const Icon(Icons.chevron_right), | ||
| onTap: () { | ||
| _showOptions(context, 'Message History', <String>[ | ||
| 'View Messages', | ||
| 'Delete Messages', | ||
| 'Archive Messages', | ||
| 'Message Settings', | ||
| ]); | ||
| }, | ||
| ), | ||
| ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Extract hardcoded strings to localization constants
The support categories and their options should be extracted to localization constants for better maintainability and internationalization support.
Create a new file lib/core/constants/support_strings.dart and move all strings there.
| void _showTicketForm(BuildContext context, String category, String subOption) { | ||
| Navigator.push( | ||
| context, | ||
| MaterialPageRoute<void>( | ||
| builder: (BuildContext context) => Scaffold( | ||
| appBar: AppBar( | ||
| title: const Text('Submit Ticket'), | ||
| leading: IconButton( | ||
| icon: const Icon(Icons.arrow_back), | ||
| onPressed: () { | ||
| Navigator.pop(context); | ||
| }, | ||
| ), | ||
| ), | ||
| body: TicketForm(category: category, subOption: subOption), | ||
| ), | ||
| ), | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for navigation operations
The navigation operations should be wrapped in try-catch blocks to handle potential errors gracefully.
Apply this diff:
void _showTicketForm(BuildContext context, String category, String subOption) {
+ try {
Navigator.push(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text('Submit Ticket'),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
+ try {
Navigator.pop(context);
+ } catch (e) {
+ debugPrint('Error navigating back: $e');
+ }
},
),
),
body: TicketForm(category: category, subOption: subOption),
),
),
);
+ } catch (e) {
+ debugPrint('Error showing ticket form: $e');
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| void _showTicketForm(BuildContext context, String category, String subOption) { | |
| Navigator.push( | |
| context, | |
| MaterialPageRoute<void>( | |
| builder: (BuildContext context) => Scaffold( | |
| appBar: AppBar( | |
| title: const Text('Submit Ticket'), | |
| leading: IconButton( | |
| icon: const Icon(Icons.arrow_back), | |
| onPressed: () { | |
| Navigator.pop(context); | |
| }, | |
| ), | |
| ), | |
| body: TicketForm(category: category, subOption: subOption), | |
| ), | |
| ), | |
| ); | |
| } | |
| void _showTicketForm(BuildContext context, String category, String subOption) { | |
| try { | |
| Navigator.push( | |
| context, | |
| MaterialPageRoute<void>( | |
| builder: (BuildContext context) => Scaffold( | |
| appBar: AppBar( | |
| title: const Text('Submit Ticket'), | |
| leading: IconButton( | |
| icon: const Icon(Icons.arrow_back), | |
| onPressed: () { | |
| try { | |
| Navigator.pop(context); | |
| } catch (e) { | |
| debugPrint('Error navigating back: $e'); | |
| } | |
| }, | |
| ), | |
| ), | |
| body: TicketForm(category: category, subOption: subOption), | |
| ), | |
| ), | |
| ); | |
| } catch (e) { | |
| debugPrint('Error showing ticket form: $e'); | |
| } | |
| } |
| final InternetConnectionBloc internetConnectionBloc = | ||
| context.read<InternetConnectionBloc>(); | ||
| if (internetConnectionBloc.state is DisconnectedInternet) { | ||
| final SharedPreferences prefs = await SharedPreferences.getInstance(); | ||
| await prefs.setString('cachedProfile', updatedProfile.toMap().toString()); | ||
| if (mounted) { | ||
| ScaffoldMessenger.of(context).showSnackBar( | ||
| const SnackBar( | ||
| content: Text( | ||
| 'No internet connection. Your data will be saved when you are online.', | ||
| ), | ||
| ), | ||
| ); | ||
| } | ||
| } else { | ||
| context.read<ProfileBloc>().add( | ||
| UpdateProfileEvent( | ||
| userId: userId, | ||
| updatedProfile: updatedProfile, | ||
| ), | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add validation and retry mechanism for offline saves
The current implementation lacks data validation and a retry mechanism for cached profiles.
- Add validation before saving:
bool _validateProfile(UserProfile profile) {
return profile.name.isNotEmpty &&
profile.email.isNotEmpty &&
EmailValidator.validate(profile.email);
}- Implement a retry mechanism for cached profiles:
Future<void> _retryCachedProfile() async {
final prefs = await SharedPreferences.getInstance();
final cachedProfile = prefs.getString('cachedProfile');
if (cachedProfile != null) {
try {
final profile = UserProfile.fromMap(cachedProfile);
await _saveProfile(profile);
await prefs.remove('cachedProfile');
} catch (e) {
// Handle parsing errors
}
}
}- Consider using a more robust caching solution like Hive or SQLite for storing multiple pending profiles.
| final InternetConnectionBloc internetConnectionBloc = | ||
| context.read<InternetConnectionBloc>(); | ||
| if (internetConnectionBloc.state is DisconnectedInternet) { | ||
| final SharedPreferences prefs = await SharedPreferences.getInstance(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle potential race conditions in connectivity check
The current implementation might have race conditions between checking connection state and saving the profile.
Consider using a more robust approach:
Future<bool> _isConnected() async {
try {
final result = await InternetAddress.lookup('example.com');
return result.isNotEmpty && result[0].rawAddress.isNotEmpty;
} on SocketException catch (_) {
return false;
}
}
This pull request introduces a new support feature to the EcoBites application, including a
SupportBlocfor managing support tickets, a new support screen, and integration with the existing application structure. The most important changes include adding theSupportBloc, creating a new support screen, and updating the dependency injection setup.New Support Feature:
lib/features/support/presentation/bloc/support_bloc.dart: AddedSupportBlocto handle support ticket submissions and retry logic for cached tickets.lib/features/support/presentation/screens/support_screen.dart: Created a new support screen with options for different support categories and a form for submitting tickets.lib/features/support/presentation/widgets/ticket_form.dart: Implemented a ticket form for users to submit support requests, with state management usingSupportBloc.Integration with Existing Application:
lib/app.dart: AddedSupportBlocto the list of BlocProviders.lib/injection_container.dart: Updated the service locator to includeSupportBloc. [1] [2]lib/route_generator.dart: Added routes for the new support screen. [1] [2]Enhancements to Profile Screen:
lib/features/profile/presentation/screens/profile_screen.dart: Added a button to navigate to the support screen and improved the save profile functionality to handle offline scenarios. [1] [2]Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Documentation
These updates improve user assistance and profile management, enhancing overall user experience.