diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 49e2d82..64708d4 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -164,6 +164,7 @@ "quotationAnalysis": "تحليل الاقتباس", "subject": "موضوعات", "description": "وصف", + "pleaseEnterDescription": "الرجاء إدخال الوصف", "supplier": "المورد", "site": "موقع", "buyer": "مشتر", @@ -648,5 +649,8 @@ "etqanRequest": "طلبات الحوادث", "selectProject": "حدد المشروع", "project": "مشروع", - "keen": "حريص" + "keen": "حريص", + "ticketNumber": "رقم التذكرة", + "ticketId": "معرف التذكرة", + "pleaseSelectProject": "الرجاء اختيار مشروع" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 1e69102..b130204 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -158,6 +158,7 @@ "subject": "Subject", "quotationAnalysis": "Quotation Analysis", "description": "Description", + "pleaseEnterDescription": "Please enter description", "supplier": "Supplier", "site": "Site", "buyer": "Buyer", @@ -646,5 +647,8 @@ "etqanRequest": "Incident Requests", "selectProject": "Select Project", "project": "Project", - "keen": "Keen" + "keen": "Keen", + "ticketNumber": "Ticket Number", + "ticketId": "Ticket ID", + "pleaseSelectProject": "Please select a project" } \ No newline at end of file diff --git a/lib/api/etqan_ovr_api_client.dart b/lib/api/etqan_ovr_api_client.dart index 3f595a4..1018177 100644 --- a/lib/api/etqan_ovr_api_client.dart +++ b/lib/api/etqan_ovr_api_client.dart @@ -93,7 +93,7 @@ class EtqanApiClient { ); } - Future createRequest(String description, int? projectID, String? attachmentBase64, bool? isAnonymous) async { + Future?> createRequest(String description, int? projectID, String? attachmentBase64, bool? isAnonymous) async { String url = "${ApiConsts.cocRest}ETQAN_CreateIncident"; Map postParams = { "P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER, @@ -111,7 +111,7 @@ class EtqanApiClient { if (json["ETQAN_CreateIncident_Response"] != null) { var response = json["ETQAN_CreateIncident_Response"]; if (response["id"] != null && response["ticketNumber"] != null) { - return 1; + return {"id": response["id"], "ticketNumber": response["ticketNumber"]}; } return null; } diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 3eef24e..9f72052 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -180,6 +180,7 @@ class CodegenLoader extends AssetLoader{ "quotationAnalysis": "تحليل الاقتباس", "subject": "موضوعات", "description": "وصف", + "pleaseEnterDescription": "الرجاء إدخال الوصف", "supplier": "المورد", "site": "موقع", "buyer": "مشتر", @@ -660,7 +661,11 @@ class CodegenLoader extends AssetLoader{ "etqanOVR": "الإبلاغ عن حادثة", "etqanRequest": "طلبات الحوادث", "selectProject": "حدد المشروع", - "project": "مشروع" + "project": "مشروع", + "keen": "حريص", + "ticketNumber": "رقم التذكرة", + "ticketId": "معرف التذكرة", + "pleaseSelectProject": "الرجاء اختيار مشروع" }; static const Map _en_US = { "mohemm": "Mohemm", @@ -822,6 +827,7 @@ static const Map _en_US = { "subject": "Subject", "quotationAnalysis": "Quotation Analysis", "description": "Description", + "pleaseEnterDescription": "Please enter description", "supplier": "Supplier", "site": "Site", "buyer": "Buyer", @@ -1308,7 +1314,11 @@ static const Map _en_US = { "etqanOVR": "Report An Incident", "etqanRequest": "Incident Requests", "selectProject": "Select Project", - "project": "Project" + "project": "Project", + "keen": "Keen", + "ticketNumber": "Ticket Number", + "ticketId": "Ticket ID", + "pleaseSelectProject": "Please select a project" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 7c74caa..6bcc80b 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -167,6 +167,7 @@ abstract class LocaleKeys { static const quotationAnalysis = 'quotationAnalysis'; static const subject = 'subject'; static const description = 'description'; + static const pleaseEnterDescription = 'pleaseEnterDescription'; static const supplier = 'supplier'; static const site = 'site'; static const buyer = 'buyer'; @@ -634,5 +635,8 @@ abstract class LocaleKeys { static const selectProject = 'selectProject'; static const project = 'project'; static const keen = 'keen'; + static const ticketNumber = 'ticketNumber'; + static const ticketId = 'ticketId'; + static const pleaseSelectProject = 'pleaseSelectProject'; } diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index 83e4c9b..b717b0f 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -150,6 +150,11 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } + // Validate description + bool isDescriptionValid() { + return description.trim().isNotEmpty; + } + // Set isAnonymous void setIsAnonymous(bool value) { isAnonymous = value; @@ -168,22 +173,21 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } // Submit request - Future submitRequest(BuildContext context) async { + Future?> submitRequest(BuildContext context) async { try { Utils.showLoading(context); - int? isSuccess = await EtqanApiClient().createRequest(description, selectedProject?.projectId, attachmentBase64, isAnonymous); + Map? response = await EtqanApiClient().createRequest(description, selectedProject?.projectId, attachmentBase64, isAnonymous); Utils.hideLoading(context); - if (isSuccess == 1) { + if (response != null) { getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); notifyListeners(); - Navigator.of(context).pop(); - return true; + return response; } - return false; + return null; } catch (ex) { Utils.hideLoading(context); Utils.handleException(ex, context, null); - return false; + return null; } } } diff --git a/lib/ui/etqan_ovr/etqan_create_request.dart b/lib/ui/etqan_ovr/etqan_create_request.dart index 3a253d9..1618711 100644 --- a/lib/ui/etqan_ovr/etqan_create_request.dart +++ b/lib/ui/etqan_ovr/etqan_create_request.dart @@ -3,6 +3,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; @@ -60,6 +61,7 @@ class _EtqanOvrCreateRequestState extends State { hint: LocaleKeys.selectProject.tr(), value: _getProjectDisplayName(provider.selectedProject), onTap: () => _showProjectSelectionSheet(context, provider), + isMandatory: true, ), 16.height, // _buildDropdownField( @@ -81,7 +83,39 @@ class _EtqanOvrCreateRequestState extends State { )).expanded, DefaultButton(LocaleKeys.submit.tr(), () async { provider.setDescription(_descriptionController.text); - await provider.submitRequest(context); + if (provider.selectedProject == null) { + Utils.showErrorDialog( + context: context, + message: LocaleKeys.pleaseSelectProject.tr(), + onOkTapped: () { + Navigator.of(context).pop(); + }, + ); + return; + } + if (!provider.isDescriptionValid()) { + Utils.showErrorDialog( + context: context, + message: LocaleKeys.pleaseEnterDescription.tr(), + onOkTapped: () { + Navigator.of(context).pop(); + }, + ); + return; + } + Map? ticketInfo = await provider.submitRequest(context); + if (ticketInfo != null) { + String ticketNumber = ticketInfo['ticketNumber'] ?? ''; + String ticketId = ticketInfo['id'] ?? ''; + String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber\n${LocaleKeys.ticketId.tr()}: $ticketId'; + Utils.showErrorDialog( + context: context, + message: successMessage, + onOkTapped: () { + Navigator.of(context).pop(); + }, + ); + } }).insideContainer, ], ); @@ -137,7 +171,7 @@ class _EtqanOvrCreateRequestState extends State { ); } - Widget _buildDropdownField({required String label, required String hint, String? value, required VoidCallback onTap}) { + Widget _buildDropdownField({required String label, required String hint, String? value, required VoidCallback onTap, bool isMandatory = false}) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(15), @@ -150,7 +184,12 @@ class _EtqanOvrCreateRequestState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(label, style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)), + Row( + children: [ + Text(label, style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)), + if (isMandatory) const Text(' *', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Colors.red, letterSpacing: -0.44)), + ], + ), const SizedBox(height: 4), Text(value ?? hint, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: value != null ? const Color(0xff2B353E) : const Color(0xff575757), letterSpacing: -0.56)), ], @@ -227,7 +266,12 @@ class _EtqanOvrCreateRequestState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(LocaleKeys.description.tr(), style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)), + Row( + children: [ + Text(LocaleKeys.description.tr(), style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)), + const Text(' *', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Colors.red, letterSpacing: -0.44)), + ], + ), GestureDetector( onTap: provider.speechEnabled