feat: implement user reporting in chat and dynamic environment-aware testimonial links
This commit is contained in:
@@ -4,7 +4,10 @@ import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||
import 'package:real_estate_mobile/core/network/api_client.dart';
|
||||
import 'package:real_estate_mobile/core/network/api_exceptions.dart';
|
||||
import 'package:real_estate_mobile/core/utils/image_url_resolver.dart';
|
||||
import 'package:real_estate_mobile/core/widgets/s3_image.dart';
|
||||
import 'package:real_estate_mobile/features/auth/presentation/providers/auth_provider.dart';
|
||||
@@ -349,38 +352,102 @@ class _ChatScreenState extends ConsumerState<ChatScreen>
|
||||
}
|
||||
|
||||
void _showReportDialog() {
|
||||
final controller = TextEditingController();
|
||||
final descController = TextEditingController();
|
||||
String selectedReason = 'Spam';
|
||||
final reasons = [
|
||||
'Spam',
|
||||
'Harassment',
|
||||
'Inappropriate Content',
|
||||
'Scam / Fraud',
|
||||
'Other',
|
||||
];
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('Report User'),
|
||||
content: TextField(
|
||||
controller: controller,
|
||||
maxLines: 3,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Describe the issue...',
|
||||
border: OutlineInputBorder(),
|
||||
builder: (ctx) => StatefulBuilder(
|
||||
builder: (ctx, setDialogState) => AlertDialog(
|
||||
title: const Text('Report User'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('Reason:', style: TextStyle(fontWeight: FontWeight.w600)),
|
||||
const SizedBox(height: 8),
|
||||
DropdownButtonFormField<String>(
|
||||
value: selectedReason,
|
||||
items: reasons.map((r) => DropdownMenuItem(value: r, child: Text(r))).toList(),
|
||||
onChanged: (v) {
|
||||
if (v != null) setDialogState(() => selectedReason = v);
|
||||
},
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: descController,
|
||||
maxLines: 3,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Additional details (optional)...',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Navigator.pop(ctx);
|
||||
await _submitReport(selectedReason, descController.text.trim());
|
||||
},
|
||||
child: const Text('Submit'),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(ctx);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Report submitted. Thank you.')),
|
||||
);
|
||||
},
|
||||
child: const Text('Submit'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _submitReport(String reason, String description) async {
|
||||
// Find the other party's userId for the report
|
||||
final conversations = ref.read(messagingProvider).conversations;
|
||||
final conv = conversations.where((c) => c.id == widget.conversationId).firstOrNull;
|
||||
if (conv == null) return;
|
||||
|
||||
// otherParty.userId is the actual user ID (for agents),
|
||||
// for regular users otherParty.id is the agentProfileId — we need the userId behind it
|
||||
final reportedUserId = conv.otherParty.userId ?? conv.otherParty.id;
|
||||
|
||||
try {
|
||||
final dio = ApiClient.instance.dio;
|
||||
await dio.post('/user-reports', data: {
|
||||
'reportedUserId': reportedUserId,
|
||||
'conversationId': widget.conversationId,
|
||||
'reason': reason,
|
||||
if (description.isNotEmpty) 'description': description,
|
||||
});
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Report submitted. Thank you.')),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
final msg = (e is DioException && e.error is ApiException)
|
||||
? (e.error as ApiException).message
|
||||
: 'Failed to submit report';
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(msg)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _handleBack() {
|
||||
// deactivate() will clear activeConversationId — no need to do it here.
|
||||
if (Navigator.of(context).canPop()) {
|
||||
|
||||
Reference in New Issue
Block a user