import 'dart:developer'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:onufitness/controller/update_acces_token_controller.dart'; import 'package:onufitness/screens/accounts/model/coach_service_offerings_response_model.dart'; import 'package:onufitness/constants/api_endpoints.dart'; import 'package:onufitness/models/master_dropdowns/coach_types_dropdown_response_model.dart'; import 'package:onufitness/services/api_services/base_api_services.dart'; import 'package:onufitness/services/local_storage_services/shared_services.dart'; import 'package:onufitness/utils/custom_sneakbar.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:http/http.dart' as http; class CoachServiceOfferingController extends GetxController { @override void onInit() { fetchCoachTypes(); getServiceOfferings(); super.onInit(); } var isServiceOfferingsLoading = false.obs; var serviceOfferingsData = Rxn(); var apiCertificates = [].obs; var isUpdatingServiceOffering = false.obs; var isAddingCertificate = false.obs; Future pickFileForAdding() async { FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: ['pdf', 'jpg', 'jpeg', 'png'], ); if (result != null) { String filePath = result.files.single.path!; await addCertificateToServer(filePath); } } void pickFileForEditing(int index) async { FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: ['pdf', 'jpg', 'jpeg', 'png'], ); if (result != null) { String filePath = result.files.single.path!; Certificate cert = apiCertificates[index]; await updateCertificateOnServer(cert.certificateId!, filePath); } } Future downloadCertificate(String filePath) async { final uri = Uri.parse(filePath); if (!await launchUrl(uri, mode: LaunchMode.inAppBrowserView)) { throw Exception('Could not launch $filePath'); } } String getShortText(String text, {int maxLength = 10}) { if (text.length <= maxLength) return text; return '${text.substring(0, maxLength)}...'; } void removeCertificateWithConfirmation(int index) { String fileName = apiCertificates[index].certificateName!; Get.dialog( AlertDialog( title: Text("Remove Certificate"), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Are you sure you want to remove this certificate?"), SizedBox(height: 10), Text( "File: $fileName", style: TextStyle(fontWeight: FontWeight.bold), ), SizedBox(height: 10), ], ), actions: [ TextButton(onPressed: () => Get.back(), child: Text("Cancel")), ElevatedButton( onPressed: () { Get.back(); _removeCertificateAtIndex(index); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white, ), child: Text("Remove"), ), ], ), ); } void _removeCertificateAtIndex(int index) async { Certificate cert = apiCertificates[index]; await deleteCertificateFromServer(cert.certificateId!); } //Update Service Offering .............................................................................. Future updateServiceOffering() async { if (selectedCoachTypesId.value == 0) { customSnackbar(title: "Error", message: "Please select a coach type"); return; } isUpdatingServiceOffering(true); try { var response = await ApiBase.putRequest( extendedURL: ApiUrl.updateServiceOffering, sendHeaders: true, body: {"coachTypeID": selectedCoachTypesId.value}, ); if (response.statusCode == 200 || response.statusCode == 201) { customSnackbar( title: "Success", message: "Service offering updated successfully", duration: 1, ); await getServiceOfferings(); } else { customSnackbar( title: "Error", message: "Failed to update service offering", duration: 1, ); } } catch (e) { customSnackbar( title: "Error", message: "Failed to update service offering", duration: 1, ); } finally { isUpdatingServiceOffering(false); } } // Delete Certificate............................................................................... RxList deleteCertificateLoading = [].obs; Future deleteCertificateFromServer(int certificateId) async { deleteCertificateLoading.add(certificateId); try { var response = await ApiBase.deleteRequest( extendedURL: "${ApiUrl.deleteCoachCertificate}/$certificateId", sendHeaders: true, body: {}, ); if (response.statusCode == 200 || response.statusCode == 204) { await getServiceOfferings(); } else { customSnackbar(title: "Error", message: "Failed to delete certificate"); } } catch (e) { log("Exception in deleteCertificateFromServer: $e"); customSnackbar( title: "Error", message: "Failed to delete certificate: ${e.toString()}", ); } finally { deleteCertificateLoading.remove(certificateId); } } // Update Certificate....................................................................................... RxList updateCertificateLoading = [].obs; Future updateCertificateOnServer( int certificateId, String filePath, ) async { updateCertificateLoading.add(certificateId); try { var request = http.MultipartRequest( 'PUT', Uri.parse("${ApiUrl.baseUrl}${ApiUrl.updateCoachCertificate}"), ); String? token = SharedServices.userAuth(); request.headers['Authorization'] = 'Bearer $token'; request.headers['accept'] = 'text/plain'; request.fields['CertificateID'] = certificateId.toString(); var file = await http.MultipartFile.fromPath('Certificates', filePath); request.files.add(file); var response = await request.send(); var responseBody = await response.stream.bytesToString(); if (response.statusCode == 200 || response.statusCode == 201) { customSnackbar( title: "Success", message: "Certificate updated successfully", duration: 1, ); await getServiceOfferings(); } else if (response.statusCode == 401) { await UpdateAccesTokenController.updateAccessToken(); await updateCertificateOnServer(certificateId, filePath); } else { log("Update certificate error: ${response.statusCode} - $responseBody"); customSnackbar( title: "Error", message: "Failed to update certificate", duration: 1, ); } } catch (e) { log("Catch: Exception in updateCertificateOnServer"); customSnackbar( title: "Error", message: "Failed to update certificate", duration: 1, ); } finally { updateCertificateLoading.remove(certificateId); } } // Add Certificate....................................................................................... Future addCertificateToServer(String filePath) async { isAddingCertificate(true); try { var request = http.MultipartRequest( 'POST', Uri.parse( "${ApiUrl.baseUrl}${ApiUrl.coachAddServiceOfferingCertificate}", ), ); String? token = SharedServices.userAuth(); request.headers['Authorization'] = 'Bearer $token'; request.headers['accept'] = 'text/plain'; request.fields['CertificateType'] = 'string'; var file = await http.MultipartFile.fromPath('Certificates', filePath); request.files.add(file); var response = await request.send(); var responseBody = await response.stream.bytesToString(); log("Add certificate error: ${response.statusCode} - $responseBody"); if (response.statusCode == 200 || response.statusCode == 201) { customSnackbar( title: "Success", message: "Certificate added successfully", duration: 1, ); await getServiceOfferings(); } else if (response.statusCode == 401) { await UpdateAccesTokenController.updateAccessToken(); await addCertificateToServer(filePath); } else { log("Add certificate error: ${response.statusCode} - $responseBody"); customSnackbar( title: "Error", message: "Failed to add certificate", duration: 1, ); } } catch (e) { log("Exception in addCertificateToServer: $e"); customSnackbar( title: "Error", message: "Failed to add certificate: ${e.toString()}", duration: 1, ); } finally { isAddingCertificate(false); } } //...........Fetch Coach Types for Dropdown.............................................................................. var isCoachTypesLoading = false.obs; var apiCoachTypeList = [].obs; var selectedCoachTypes = "".obs; RxList localCoachTypesNameList = [].obs; RxInt selectedCoachTypesId = 0.obs; Future fetchCoachTypes() async { isCoachTypesLoading(true); try { var response = await ApiBase.getRequest( extendedURL: ApiUrl.fetchCoachTypes, sendHeaders: true, ); if (response.statusCode == 200 || response.statusCode == 201) { var responseData = coachTypesResponseModelFromJson(response.body); if (responseData.isSuccess == true) { apiCoachTypeList.assignAll(responseData.data ?? []); localCoachTypesNameList.clear(); for (var coach in responseData.data!) { localCoachTypesNameList.add(coach.typeName.toString()); } } else { var responseData = coachTypesResponseModelFromJson(response.body); customSnackbar( title: "Error", message: responseData.message ?? "Failed to get Coach Types", ); } } else { var responseData = coachTypesResponseModelFromJson(response.body); customSnackbar( title: "Error", message: responseData.message ?? "Failed to get Coach Types", ); } } catch (e) { log("Exception: $e"); customSnackbar(title: "Error", message: "Failed to get Coach Types"); } finally { isCoachTypesLoading(false); } } //...........Get Service Offerings API Call.............................................................................. Future getServiceOfferings() async { isServiceOfferingsLoading(true); try { var response = await ApiBase.getRequest( extendedURL: ApiUrl.getServiceOfferings, sendHeaders: true, ); log(response.body); if (response.statusCode == 200 || response.statusCode == 201) { var responseData = getServiceOfferingsResponseModelFromJson( response.body, ); if (responseData.isSuccess == true && responseData.data != null) { serviceOfferingsData.value = responseData.data; apiCertificates.assignAll(responseData.data?.certificates ?? []); if (responseData.data?.coachTypeName != null) { selectedCoachTypes.value = responseData.data!.coachTypeName!; selectedCoachTypesId.value = responseData.data!.coachTypeId ?? 0; } log("Service Offerings loaded successfully"); } else { customSnackbar( title: "Error", message: responseData.message ?? "Failed to get Service Offerings", ); } } else { log("API Error: Status Code ${response.statusCode}"); log("Response Body: ${response.body}"); customSnackbar( title: "Error", message: "Failed to get Service Offerings", ); } } catch (e) { log("Exception in getServiceOfferings: $e"); customSnackbar( title: "Error", message: "Failed to get Service Offerings}", ); } finally { isServiceOfferingsLoading(false); } } // Method to refresh/reload service offerings........................................................................ Future refreshServiceOfferings() async { await getServiceOfferings(); } }