From 257b803cce78c5791fac4443167fb29d3838e915 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Mon, 2 Mar 2026 15:01:29 +0300 Subject: [PATCH] QIPS-1205 --- .../etqan_ovr/etqan_get_requests_model.dart | 12 ++ lib/provider/etqan_ovr_provider.dart | 13 +- lib/ui/etqan_ovr/etqan_ovr_home.dart | 67 +++++++- lib/ui/etqan_ovr/etqan_request_detailed.dart | 156 +++++++++++------- 4 files changed, 183 insertions(+), 65 deletions(-) diff --git a/lib/models/etqan_ovr/etqan_get_requests_model.dart b/lib/models/etqan_ovr/etqan_get_requests_model.dart index c59e171..ac4911b 100644 --- a/lib/models/etqan_ovr/etqan_get_requests_model.dart +++ b/lib/models/etqan_ovr/etqan_get_requests_model.dart @@ -24,12 +24,18 @@ class EtqanGetEmployeeOvrRequestsResponse { String? createdDate; String? description; String? id; + bool? isAnonymous; + String? status; + String? statusAr; String? ticketNumber; EtqanGetEmployeeOvrRequestsResponse({ this.createdDate, this.description, this.id, + this.isAnonymous, + this.status, + this.statusAr, this.ticketNumber, }); @@ -41,6 +47,9 @@ class EtqanGetEmployeeOvrRequestsResponse { createdDate: json["createdDate"], description: json["description"], id: json["id"], + isAnonymous: json["isAnonymous"], + status: json["status"], + statusAr: json["statusAr"], ticketNumber: json["ticketNumber"], ); @@ -48,6 +57,9 @@ class EtqanGetEmployeeOvrRequestsResponse { "createdDate": createdDate, "description": description, "id": id, + "isAnonymous": isAnonymous, + "status": status, + "statusAr": statusAr, "ticketNumber": ticketNumber, }; } diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index a7cb842..b4f2eb1 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -17,6 +17,9 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? getEtqanEmployeeIncidnetRequest; bool isLoading = false; String? _ticketId; + String? _currentStatus; + String? _currentStatusAr; + bool? _currentIsAnonymous; // Speech to text state final SpeechToText _speechToText = SpeechToText(); @@ -34,10 +37,16 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { // Getter for ticketId String get getTicketId => _ticketId ?? ''; + String get getCurrentStatus => _currentStatus ?? ''; + String get getCurrentStatusAr => _currentStatusAr ?? ''; + bool get getCurrentIsAnonymous => _currentIsAnonymous ?? false; - // Setter for ticketId - void setTicketId(String ticketId) { + // Setter for ticketId with status and isAnonymous + void setTicketId(String ticketId, {String? status, String? statusAr, bool? isAnonymous}) { _ticketId = ticketId; + _currentStatus = status; + _currentStatusAr = statusAr; + _currentIsAnonymous = isAnonymous; notifyListeners(); } diff --git a/lib/ui/etqan_ovr/etqan_ovr_home.dart b/lib/ui/etqan_ovr/etqan_ovr_home.dart index 80a27c6..b55b4c0 100644 --- a/lib/ui/etqan_ovr/etqan_ovr_home.dart +++ b/lib/ui/etqan_ovr/etqan_ovr_home.dart @@ -1,4 +1,3 @@ - import 'package:easy_localization/easy_localization.dart' as lclize; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; @@ -16,6 +15,7 @@ import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:provider/provider.dart'; import 'package:intl/src/intl/text_direction.dart' as intl; +import 'package:sizer/sizer.dart'; class EtqanOvrHome extends StatefulWidget { const EtqanOvrHome({Key? key}) : super(key: key); @@ -33,6 +33,18 @@ class _EtqanOvrHomeState extends State { }); } + Color _getStatusColor(String status) { + String statusLower = status.toLowerCase(); + if (statusLower.contains('open') || statusLower.contains('مفتوح')) { + return const Color(0xff2196F3); // Blue for open + } else if (statusLower.contains('progress') || statusLower.contains('قيد التنفيذ')) { + return const Color(0xffFF9800); // Orange for in progress + } else if (statusLower.contains('closed') || statusLower.contains('مغلق')) { + return const Color(0xff4CAF50); // Green for closed + } + return MyColors.grey70Color; // Default gray + } + @override Widget build(BuildContext context) { return Scaffold( @@ -51,7 +63,7 @@ class _EtqanOvrHomeState extends State { EtqanGetEmployeeOvrRequestsResponse data = provider.getEtqanEmployeeRequestsList![index]; return InkWell( onTap: () { - context.read().setTicketId(data.ticketNumber ?? ''); + context.read().setTicketId(data.ticketNumber ?? '', status: data.status, statusAr: data.statusAr, isAnonymous: data.isAnonymous); Navigator.pushNamed(context, AppRoutes.etqanGetIncidientRequest); }, child: Container( @@ -64,6 +76,50 @@ class _EtqanOvrHomeState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Row( + children: [ + Expanded( + child: Wrap( + spacing: 8, + runSpacing: 8, + children: [ + if (data.status != null && data.status!.isNotEmpty) + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: _getStatusColor(data.status ?? "").withOpacity(0.1), + borderRadius: BorderRadius.circular(6), + border: Border.all(color: _getStatusColor(data.status ?? "").withOpacity(0.3), width: 1), + ), + child: (AppState().isArabic(context) ? (data.statusAr ?? "") : (data.status ?? "")).toText11( + color: _getStatusColor(data.status ?? ""), + isBold: true, + ), + ), + if (data.isAnonymous == true) + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: MyColors.grey70Color.withOpacity(0.15), + borderRadius: BorderRadius.circular(6), + border: Border.all(color: MyColors.grey70Color.withOpacity(0.3), width: 1), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.visibility_off, size: 12, color: MyColors.grey70Color), + const SizedBox(width: 4), + (AppState().isArabic(context) ? "مجهول" : "Anonymous").toText11(color: MyColors.grey70Color, isBold: true), + ], + ), + ), + ], + ), + ), + const SizedBox(width: 8), + ], + ), + 8.height, Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -72,11 +128,12 @@ class _EtqanOvrHomeState extends State { ], ), 8.height, + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [(data.description ?? "").toText12(color: MyColors.grey57Color).expanded]), + 3.height, Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.end, children: [ - (data.description ?? "").toText12(color: MyColors.grey57Color).expanded, - const SizedBox(width: 5,), RotatedBox( quarterTurns: AppState().isArabic(context) ? 2 : 0, child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.grey70Color, width: 16, height: 16), diff --git a/lib/ui/etqan_ovr/etqan_request_detailed.dart b/lib/ui/etqan_ovr/etqan_request_detailed.dart index 6f9aebc..41d11c6 100644 --- a/lib/ui/etqan_ovr/etqan_request_detailed.dart +++ b/lib/ui/etqan_ovr/etqan_request_detailed.dart @@ -4,6 +4,7 @@ import 'dart:typed_data'; 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/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; @@ -25,9 +26,21 @@ class EtqanOvrRequestDetailed extends StatefulWidget { } class _EtqanOvrRequestDetailedState extends State { - List get fieldOrder => ['Project', 'Created', 'Occurrence Time', 'OVR Reference No', 'Involved Employee Number', 'Description']; - - List get hiddenFields => ['OVR Id', 'Is Anonymous']; + List get fieldOrder => ['Status', 'Project', 'Created', 'Is Anonymous', 'Occurrence Time', 'OVR Reference No', 'Involved Employee Number', 'Description']; + + List get hiddenFields => ['OVR Id']; + + Color _getStatusColor(String status) { + String statusLower = status.toLowerCase(); + if (statusLower.contains('open') || statusLower.contains('مفتوح')) { + return const Color(0xff2196F3); // Blue for open + } else if (statusLower.contains('progress') || statusLower.contains('قيد التنفيذ')) { + return const Color(0xffFF9800); // Orange for in progress + } else if (statusLower.contains('closed') || statusLower.contains('مغلق')) { + return const Color(0xff4CAF50); // Green for closed + } + return MyColors.grey70Color; // Default gray + } Future _viewAttachment(BuildContext context, String base64Data) async { try { @@ -47,15 +60,33 @@ class _EtqanOvrRequestDetailedState extends State { } } - List _getOrderedList(List list) { + List _getOrderedList(List list, EtqanOvrProviderModel provider) { List orderedList = []; List filteredList = list.where((EtqanGetIncidentRequestResponse item) => !hiddenFields.any((f) => f.toLowerCase() == item.key?.toLowerCase())).toList(); for (String fieldName in fieldOrder) { - var item = filteredList.firstWhere((e) => e.key?.toLowerCase() == fieldName.toLowerCase(), orElse: () => EtqanGetIncidentRequestResponse()); - if (item.key != null) { - orderedList.add(item); + // Check if this is Status or Is Anonymous - inject from provider + if (fieldName.toLowerCase() == 'status' && provider.getCurrentStatus.isNotEmpty) { + orderedList.add(EtqanGetIncidentRequestResponse( + key: 'Status', + keyAr: 'الحالة', + value: provider.getCurrentStatus, + valueAr: provider.getCurrentStatusAr.isNotEmpty ? provider.getCurrentStatusAr : provider.getCurrentStatus, + )); + } else if (fieldName.toLowerCase() == 'is anonymous') { + orderedList.add(EtqanGetIncidentRequestResponse( + key: 'Is Anonymous', + keyAr: 'مجهول', + value: provider.getCurrentIsAnonymous.toString(), + valueAr: provider.getCurrentIsAnonymous.toString(), + )); + } else { + // Regular field from API + var item = filteredList.firstWhere((e) => e.key?.toLowerCase() == fieldName.toLowerCase(), orElse: () => EtqanGetIncidentRequestResponse()); + if (item.key != null) { + orderedList.add(item); + } } } @@ -88,7 +119,7 @@ class _EtqanOvrRequestDetailedState extends State { return Utils.getNoDataWidget(context); } - List orderedList = _getOrderedList(provider.getEtqanEmployeeIncidnetRequest!); + List orderedList = _getOrderedList(provider.getEtqanEmployeeIncidnetRequest!, provider); return SingleChildScrollView( physics: const BouncingScrollPhysics(), @@ -108,6 +139,8 @@ class _EtqanOvrRequestDetailedState extends State { EtqanGetIncidentRequestResponse data = entry.value; bool isLast = index == orderedList.length - 1; bool isAttachment = data.key?.toLowerCase() == 'attachment'; + bool isStatus = data.key?.toLowerCase() == 'status'; + bool isAnonymous = data.key?.toLowerCase() == 'is anonymous'; String displayKey = context.locale.languageCode == "ar" ? (data.keyAr ?? data.key ?? "") : (data.key ?? ""); String displayValue = context.locale.languageCode == "ar" ? (data.valueAr ?? data.value ?? "") : (data.value ?? ""); @@ -125,58 +158,65 @@ class _EtqanOvrRequestDetailedState extends State { 8.width, Expanded( flex: 3, - child: - isAttachment && hasSubValues - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: - data.subValues!.asMap().entries.map((entry) { - int subIndex = entry.key; - String base64Data = entry.value; - return Padding( - padding: EdgeInsets.only(bottom: subIndex < data.subValues!.length - 1 ? 8.0 : 0), - child: GestureDetector( - onTap: () => _viewAttachment(context, base64Data), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: context.locale.languageCode == "ar" ? MainAxisAlignment.end : MainAxisAlignment.start, - children: [ - Text( - data.subValues!.length > 1 ? '${LocaleKeys.viewAttachment.tr()} ${subIndex + 1}' : LocaleKeys.viewAttachment.tr(), - // textAlign: context.locale.languageCode == "ar" ? TextAlign.start : TextAlign.start, - style: const TextStyle( - fontSize: 14, - color: MyColors.green9CColor, - decoration: TextDecoration.underline, - decorationColor: MyColors.green9CColor, + child: isStatus + ? displayValue.toText14( + color: _getStatusColor(displayValue), + isBold: true, + ) + : isAnonymous + ? (displayValue.toLowerCase() == 'true' || displayValue.toLowerCase() == 'yes' || displayValue == '1' + ? (context.locale.languageCode == "ar" ? "نعم" : "Yes") + : (context.locale.languageCode == "ar" ? "لا" : "No") + ).toText14(color: MyColors.darkTextColor) + : isAttachment && hasSubValues + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: data.subValues!.asMap().entries.map((entry) { + int subIndex = entry.key; + String base64Data = entry.value; + return Padding( + padding: EdgeInsets.only(bottom: subIndex < data.subValues!.length - 1 ? 8.0 : 0), + child: GestureDetector( + onTap: () => _viewAttachment(context, base64Data), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: context.locale.languageCode == "ar" ? MainAxisAlignment.end : MainAxisAlignment.start, + children: [ + Text( + data.subValues!.length > 1 ? '${LocaleKeys.viewAttachment.tr()} ${subIndex + 1}' : LocaleKeys.viewAttachment.tr(), + style: const TextStyle( + fontSize: 14, + color: MyColors.green9CColor, + decoration: TextDecoration.underline, + decorationColor: MyColors.green9CColor, + ), ), - ), - ], - ), - ), - ); - }).toList(), - ) - : hasSubValues - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (displayValue.isNotEmpty) displayValue.toText14(color: MyColors.darkTextColor), - if (displayValue.isNotEmpty) 8.height, - ...data.subValues! - .map( - (subValue) => Padding( - padding: const EdgeInsets.only(bottom: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [const Text("• ", style: TextStyle(fontSize: 14)), Expanded(child: subValue.toText14(color: MyColors.darkTextColor))], + ], + ), ), - ), - ) - .toList(), - ], - ) - : (displayValue.isNotEmpty ? displayValue : "-").toText14(color: MyColors.darkTextColor), + ); + }).toList(), + ) + : hasSubValues + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (displayValue.isNotEmpty) displayValue.toText14(color: MyColors.darkTextColor), + if (displayValue.isNotEmpty) 8.height, + ...data.subValues! + .map( + (subValue) => Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [const Text("• ", style: TextStyle(fontSize: 14)), Expanded(child: subValue.toText14(color: MyColors.darkTextColor))], + ), + ), + ) + .toList(), + ], + ) + : (displayValue.isNotEmpty ? displayValue : "-").toText14(color: MyColors.darkTextColor), ), ], ),