import 'dart:convert'; import 'dart:io'; 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'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart'; import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:provider/provider.dart'; import 'package:open_filex/open_filex.dart'; import 'package:path_provider/path_provider.dart'; class EtqanOvrRequestDetailed extends StatefulWidget { const EtqanOvrRequestDetailed({Key? key}) : super(key: key); @override _EtqanOvrRequestDetailedState createState() => _EtqanOvrRequestDetailedState(); } class _EtqanOvrRequestDetailedState extends State { 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 { Uint8List bytes = base64.decode(base64Data); String dir = (await getApplicationDocumentsDirectory()).path; String ext = 'pdf'; if (base64Data.startsWith('/9j/')) { ext = 'jpg'; } else if (base64Data.startsWith('iVBORw0KGgo')) { ext = 'png'; } File file = File("$dir/${DateTime.now().millisecondsSinceEpoch}.$ext"); await file.writeAsBytes(bytes); OpenFilex.open(file.path); } catch (e) { Utils.showToast("Cannot open attachment."); } } 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) { // 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); } } } for (var item in filteredList) { if (!fieldOrder.any((f) => f.toLowerCase() == item.key?.toLowerCase())) { orderedList.add(item); } } return orderedList; } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { EtqanOvrProviderModel provider = context.read(); provider.fetchEtqanEmployeeIncidentRequests(context, provider.getTicketId); }); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBarWidget(context, title: LocaleKeys.incidentDetails.tr()), body: Consumer( builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) { if (provider.getEtqanEmployeeIncidnetRequest == null || provider.getEtqanEmployeeIncidnetRequest!.isEmpty) { return Utils.getNoDataWidget(context); } List orderedList = _getOrderedList(provider.getEtqanEmployeeIncidnetRequest!, provider); return SingleChildScrollView( physics: const BouncingScrollPhysics(), padding: const EdgeInsets.all(16), child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(15), border: Border.all(color: const Color(0xffefefef), width: 1), boxShadow: [BoxShadow(color: Colors.black.withValues(alpha: 0.05), blurRadius: 10, offset: const Offset(0, 2))], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: orderedList.asMap().entries.map((MapEntry entry) { int index = entry.key; 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 ?? ""); bool hasSubValues = data.subValues != null && data.subValues!.isNotEmpty; return Column( children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(flex: 2, child: displayKey.toText12(isBold: true, color: MyColors.grey57Color)), 8.width, Expanded( flex: 3, 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), ), ], ), ), if (!isLast) const Padding(padding: EdgeInsets.only(left: 14, right: 14), child: Divider(height: 1, thickness: 1, color: Color(0xffefefef))), ], ); }).toList(), ), ), ); }, ).paddingOnly(bottom: 20), ); } }