Files
Xpress-rider/lib/controllers/support_ticket.dart

209 lines
5.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'dart:io';
import 'dart:math' show Random;
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:minio/io.dart';
import 'package:minio/minio.dart';
import 'package:nearle/Models/supportticket/support_ticket.dart';
// Minimal local stub for DigitalOcean Spaces client to avoid undefined name errors.
// Replace this with a real package or implementation for production uploads.
class dospace {
static DOSpaceClient DOSpace({
required String region,
required String accessKey,
required String secretKey,
}) =>
DOSpaceClient(region: region, accessKey: accessKey, secretKey: secretKey);
static final ACL = _ACL();
}
class _ACL {
final String publicRead = 'public-read';
}
class DOSpaceClient {
final String region;
final String accessKey;
final String secretKey;
DOSpaceClient({
required this.region,
required this.accessKey,
required this.secretKey,
});
Future<void> putObject({
required String bucketName,
required String objectName,
required File file,
required String acl,
required String contentType,
}) async {
// No-op stub: implement actual upload logic here or use a proper package.
await Future<void>.value();
}
}
class SupportTicketController extends GetxController {
final RxList<SupportTicketModel> tickets = <SupportTicketModel>[].obs;
final RxBool isLoading = true.obs;
final RxString errorMessage = ''.obs;
final RxBool isSubmitting = false.obs;
@override
void onInit() {
super.onInit();
fetchTickets();
}
// ---------- FETCH TICKETS ----------
Future<void> fetchTickets() async {
try {
isLoading(true);
errorMessage('');
const userId = 1242;
final url = Uri.parse(
'https://jupiter.nearle.app/live/api/v1/partners/getridersupport/?userid=$userId');
final response = await http.get(url, headers: {
'Accept': 'application/json',
});
if (response.statusCode != 200) {
throw Exception('Server error: ${response.statusCode}');
}
final Map<String, dynamic> jsonResponse = json.decode(response.body);
if (jsonResponse['status'] != true) {
throw Exception(jsonResponse['message'] ?? 'Unknown error');
}
final List<dynamic> data = jsonResponse['data'];
tickets.assignAll(data.map((e) => SupportTicketModel.fromJson(e)).toList());
} catch (e) {
errorMessage(e.toString());
} finally {
isLoading(false);
}
}
// ---------- UPLOAD IMAGE TO DO SPACES ----------
Future<String?> uploadImageToDOSpaces(File imageFile, int userId) async {
try {
final rng = Random();
const String region = "sgp1";
const String accessKey = "DO00NQER7N2FRYZAB2HR";
const String secretKey = "nMDewX25IBEu1FM5dakK+v28/WbW3TzBAwq913+dxP0";
const String bucketName = "nearle";
const String folderName = "support";
// File name
final String fileName = 'ticket-${rng.nextInt(10000)}-$userId.jpg';
// Object path inside the bucket
final String objectPath = "$folderName/$fileName";
// CDN URL you want
final String cdnUrl = "https://images.nearle.app/$objectPath";
// Initialize Minio
final minio = Minio(
endPoint: "$region.digitaloceanspaces.com",
accessKey: accessKey,
secretKey: secretKey,
region: region,
useSSL: true,
);
print("Uploading: $objectPath");
// Upload to DO Spaces
await minio.fPutObject(
bucketName,
objectPath,
imageFile.path,
metadata: {
"Content-Type": "image/jpeg",
"x-amz-acl": "public-read",
},
);
print("Uploaded Successfully: $cdnUrl");
return cdnUrl;
} catch (e) {
print("Upload error: $e");
Get.snackbar("Error", "Image upload failed.");
return null;
}
}
// ---------- CREATE TICKET ----------
// ---------- CREATE TICKET ----------
Future<bool> createTicket({
required int userid,
required String category,
required String priority,
required String subject,
required String issue,
List<XFile>? attachments,
}) async {
try {
isSubmitting(true);
String imageUrl = "";
// Upload first image if attached
if (attachments != null && attachments.isNotEmpty) {
final XFile xFile = attachments.first;
final File file = File(xFile.path);
final uploadedUrl = await uploadImageToDOSpaces(file, userid);
// Only assign if a valid URL (short length)
if (uploadedUrl != null && uploadedUrl.length < 200) {
imageUrl = uploadedUrl;
} else {
print("⚠️ Skipping image URL because its too long or invalid.");
}
}
// Create ticket request body
final Map<String, dynamic> payload = {
'userid': userid,
'category': category,
'priority': priority,
'subject': subject,
'issue': issue,
'image': imageUrl, // ✅ Always short string or empty
};
final response = await http.post(
Uri.parse('https://jupiter.nearle.app/live/api/v1/partners/createridersupport/'),
headers: {'Accept': 'application/json', 'Content-Type': 'application/json'},
body: jsonEncode(payload),
);
if (response.statusCode != 200) {
throw Exception('Ticket creation failed: ${response.statusCode}');
}
final jsonResponse = jsonDecode(response.body);
if (jsonResponse['status'] != true) {
throw Exception(jsonResponse['message'] ?? 'Unknown error');
}
await fetchTickets(); // Refresh list after success
return true;
} catch (e) {
errorMessage(e.toString());
return false;
} finally {
isSubmitting(false);
}
}
}