383 lines
13 KiB
Dart
383 lines
13 KiB
Dart
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<ServiceOfferingsData>();
|
|
var apiCertificates = <Certificate>[].obs;
|
|
var isUpdatingServiceOffering = false.obs;
|
|
var isAddingCertificate = false.obs;
|
|
|
|
Future<void> 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<void> 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<void> 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<int> deleteCertificateLoading = <int>[].obs;
|
|
Future<void> 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<int> updateCertificateLoading = <int>[].obs;
|
|
|
|
Future<void> 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<void> 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 = <CoachTypes>[].obs;
|
|
var selectedCoachTypes = "".obs;
|
|
RxList<String> localCoachTypesNameList = <String>[].obs;
|
|
RxInt selectedCoachTypesId = 0.obs;
|
|
|
|
Future<void> 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<void> 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<void> refreshServiceOfferings() async {
|
|
await getServiceOfferings();
|
|
}
|
|
}
|