Refactor laboratory result handling to support multiple special results and improve attachment display

ipd-changes-for-vida-plus
taha 4 weeks ago
parent 32c84ac1ca
commit ce488e6954

@ -1,6 +1,8 @@
import 'lab_result.dart';
class PatientLabSpecialResult {
String? SetupID;
String? ProjectID;
String? invoiceNo;
String? moduleID;
String? resultData;
@ -9,6 +11,7 @@ class PatientLabSpecialResult {
List<String>? FileNameWithExtensionList;
List<UploadedDocument>? UploadedDocuments;
bool? IsLabTestAttachment; // for the attachment icon in the lab result list
dynamic LabAccessionNo;
PatientLabSpecialResult(
{this.invoiceNo,
@ -21,7 +24,10 @@ class PatientLabSpecialResult {
this.IsLabTestAttachment});
PatientLabSpecialResult.fromJson(Map<String, dynamic> json) {
SetupID = json['SetupID'];
ProjectID = json['ProjectID'].toString();
invoiceNo = json['InvoiceNo'];
LabAccessionNo = json['LabAccessionNo'];
moduleID = json['ModuleID'];
resultData = json['ResultData'];
resultDataHTML = json['ResultDataHTML'];

@ -47,7 +47,7 @@ class _LaboratoryResultPageState extends State<LaboratoryResultPage> {
LaboratoryResultWidget(
onTap: () async {},
billNo: widget.patientLabOrders.invoiceNo!,
details: model.patientLabSpecialResult.length > 0 ? model.patientLabSpecialResult[0].resultDataHTML! : "",
details: model.patientLabSpecialResult,
orderNo: widget.patientLabOrders.orderNo!,
patientLabOrder: widget.patientLabOrders,
patient: widget.patient,

@ -1,5 +1,7 @@
import 'package:doctor_app_flutter/config/size_config.dart';
import 'package:doctor_app_flutter/core/model/labs/lab_result.dart';
import 'package:doctor_app_flutter/core/model/labs/patient_lab_orders.dart';
import 'package:doctor_app_flutter/core/model/labs/patient_lab_special_result.dart';
import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart';
import 'package:doctor_app_flutter/core/viewModel/labs_view_model.dart';
import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart';
@ -17,7 +19,7 @@ import 'package:provider/provider.dart';
class LaboratoryResultWidget extends StatefulWidget {
final GestureTapCallback? onTap;
final String? billNo;
final String? details;
final List<PatientLabSpecialResult>? details;
final String? orderNo;
final PatientLabOrders? patientLabOrder;
final PatiantInformtion? patient;
@ -147,7 +149,7 @@ class _LaboratoryResultWidgetState extends State<LaboratoryResultWidget> {
SizedBox(
height: 15,
),
if (widget.details != null && widget.details!.isNotEmpty)
if (widget.details?.isNotEmpty == true)
Column(
children: [
InkWell(
@ -200,15 +202,81 @@ class _LaboratoryResultWidgetState extends State<LaboratoryResultWidget> {
bottomRight: Radius.circular(5.0),
)),
duration: Duration(milliseconds: 7000),
child: Container(
width: double.infinity,
child: !Utils.isTextHtml(widget.details!)
? AppText(
widget.details ?? TranslationBase.of(context).noDataAvailable,
)
: Html(
data: widget.details ?? TranslationBase.of(context).noDataAvailable,
child: ListView.separated(
separatorBuilder: (context, index) => Divider(
color: Colors.grey[300],
thickness: 1,
),
itemCount: widget.details?.length ?? 0,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
String? resultData;
try {
resultData = (widget.details?[index])?.resultDataHTML?.toString();
} catch (_) {
resultData = null;
}
final displayData = (resultData == null || resultData.trim().isEmpty)
? TranslationBase.of(context).noDataAvailable
: resultData;
return Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
!Utils.isTextHtml(displayData)
? AppText(displayData)
: Html(data: displayData),
],
),
),
Visibility(
visible: widget.details?[index].IsLabTestAttachment ?? false,
child: InkWell(
onTap: () async {
var labAccessNumber = widget.details?[index].LabAccessionNo;
// if (widget.details?[index].FileNameWithExtensionList?.isNotEmpty == true || widget.details?[index].FileNameWithExtensionList?.length == 1) {
// await model.getLabAttachments(patient, labAccessNumber: labAccessNumber, FileName: widget.details?[index].FileNameWithExtensionList?.first);
// model.openPDF();
// return;
// }
//
// if (widget.details?[index].UploadedDocuments?.isNotEmpty == true || widget.details?[index].UploadedDocuments?.length == 1) {
// await model.getLabAttachments(patient, labAccessNumber: labAccessNumber, uploadedDocument: widget.details?[index].UploadedDocuments?.first);
// model.openPDF();
// return;
// }
showUploadedDocumentsBottomSheet(
context,
model,
documents: widget.details?[index].UploadedDocuments,
fileName: widget.details?[index].FileNameWithExtensionList,
labAccessNumber: labAccessNumber,
projectID: int.parse(widget.details?[index].ProjectID??"0"),
setupID: widget.details?[index].SetupID);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AppText(
TranslationBase.of(context).showAttachment,
textDecoration: TextDecoration.underline,
color: Colors.red.shade700,
fontSize: SizeConfig.textMultiplier! * 1.2,
fontWeight: FontWeight.w700,
),
],
),
),
),
],
);
},
),
),
SizedBox(
@ -226,4 +294,113 @@ class _LaboratoryResultWidgetState extends State<LaboratoryResultWidget> {
),
);
}
void showUploadedDocumentsBottomSheet(
BuildContext context, LabsViewModel model, {
List<UploadedDocument>? documents,
List<String>? fileName,
String? labAccessNumber,
int? projectID,
String? setupID,
}) {
const double kItemHeight = 66.0; // ListTile with contentPadding: 10
final double screenHeight = MediaQuery.of(context).size.height;
final double maxSheetHeight = screenHeight * 0.5;
final double minSheetHeight = (kItemHeight + 100).clamp(0, maxSheetHeight);
showModalBottomSheet(
context: context,
isScrollControlled: true, // lets the sheet respect custom height constraints
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
minHeight: minSheetHeight,
maxHeight: maxSheetHeight,
),
child: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Drag handle
Container(
margin: const EdgeInsets.symmetric(vertical: 8),
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(2),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Align(
alignment: AlignmentDirectional.centerStart,
child: Text(
TranslationBase.of(context).selectAnAttachment,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
Flexible(
child: Padding(
padding: const EdgeInsets.all(16),
child: Material(
color: const Color(0X55F2F2F2),
child: ListView.separated(
shrinkWrap: true,
padding: EdgeInsets.zero,
itemCount: documents?.length ?? fileName?.length ?? 0,
separatorBuilder: (context, index) => Padding(
padding: const EdgeInsets.all(8.0),
child: const Divider(height: 1, color: Colors.grey),
),
itemBuilder: (context, index) {
final docName = documents?[index]?.fileName ?? fileName?[index];
return ListTile(
contentPadding: const EdgeInsets.all(10),
title: Text(
docName ?? "Unnamed Document",
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
trailing: const Icon(
Icons.chevron_right,
color: Colors.grey,
),
onTap: () async {
Navigator.pop(context);
if (documents?.isNotEmpty == true) {
await model.getLabAttachments(widget.patient!, uploadedDocument: documents![index], projectID: projectID, setupID: setupID);
model.openPDF();
}
if (fileName?.isNotEmpty == true) {
await model.getLabAttachments(widget.patient!, labAccessNumber: labAccessNumber, FileName: fileName![index], projectID: projectID, setupID: setupID);
model.openPDF();
}
},
);
},
),
),
),
),
const SizedBox(height: 8),
],
),
),
);
},
);
}
}

Loading…
Cancel
Save