Pharmacy invoice implemented

pull/317/head
haroon amjad 1 month ago
parent 469479d7cb
commit a9d085098f

@ -209,7 +209,7 @@ class ApiClientImp implements ApiClient {
}
body['TokenID'] = "@dm!n";
// body['PatientID'] = 5787639;
// body['PatientID'] = 1624918;
// body['PatientTypeID'] = 1;
// body['PatientOutSA'] = 0;
// body['SessionID'] = "45786230487560q";

@ -4,7 +4,7 @@ import 'package:hmg_patient_app_new/core/enums.dart';
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.preProd;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
@ -867,6 +867,7 @@ var GET_DOCTOR_LIST_CALCULATION = "Services/Doctors.svc/REST/GetCallculationDoct
// var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = "Services/Patients.svc/REST/GetDentalAppointments";
var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = 'Services/Patients.svc/REST/GetAllInvoices';
var GET_ALL_PHARMACY_INVOICES = 'Services/Patients.svc/REST/GetAllPharmacyInvoices';
var GET_DENTAL_APPOINTMENT_INVOICE = "Services/Patients.svc/REST/HIS_eInvoiceForDentalByAppointmentNo";
var SEND_DENTAL_APPOINTMENT_INVOICE_EMAIL = "Services/Notifications.svc/REST/SendInvoiceForDental";
@ -990,6 +991,8 @@ const UPLOAD_PROFILE_IMAGE = 'Services/Patients.svc/REST/Patient_InsertProfileIm
const DOWNLOAD_INVOICE_PDF = 'Services/Notifications.svc/REST/DownloadInvoiceReport';
const DOWNLOAD_PHARMACY_INVOICE_PDF = 'Services/Notifications.svc/REST/DownloadInvoiceReport';
class ApiKeyConstants {
static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng';
}

@ -0,0 +1,92 @@
class GetPharmacyInvoicesResponseModel {
String? setupId;
int? projectID;
int? patientID;
int? appointmentNo;
String? appointmentDate;
dynamic appointmentDateN;
int? clinicID;
int? doctorID;
int? invoiceNo;
int? status;
String? arrivedOn;
String? doctorName;
String? doctorNameN;
String? displayInvoiceNo;
String? clinicName;
double? decimalDoctorRate;
String? doctorImageURL;
num? doctorRate;
num? patientNumber;
String? projectName;
GetPharmacyInvoicesResponseModel(
{this.setupId,
this.projectID,
this.patientID,
this.appointmentNo,
this.appointmentDate,
this.appointmentDateN,
this.clinicID,
this.doctorID,
this.invoiceNo,
this.status,
this.arrivedOn,
this.doctorName,
this.doctorNameN,
this.displayInvoiceNo,
this.clinicName,
this.decimalDoctorRate,
this.doctorImageURL,
this.doctorRate,
this.patientNumber,
this.projectName});
GetPharmacyInvoicesResponseModel.fromJson(Map<String, dynamic> json) {
setupId = json['SetupId'];
projectID = json['ProjectID'];
patientID = json['PatientID'];
appointmentNo = json['AppointmentNo'];
appointmentDate = json['AppointmentDate'];
appointmentDateN = json['AppointmentDateN'];
clinicID = json['ClinicID'];
doctorID = json['DoctorID'];
invoiceNo = json['InvoiceNo'];
status = json['Status'];
arrivedOn = json['ArrivedOn'];
doctorName = json['DoctorName'];
doctorNameN = json['DoctorNameN'];
displayInvoiceNo = json['DisplayInvoiceNo'];
clinicName = json['ClinicName'];
decimalDoctorRate = json['DecimalDoctorRate'];
doctorImageURL = json['DoctorImageURL'];
doctorRate = json['DoctorRate'];
patientNumber = json['PatientNumber'];
projectName = json['ProjectName'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['SetupId'] = this.setupId;
data['ProjectID'] = this.projectID;
data['PatientID'] = this.patientID;
data['AppointmentNo'] = this.appointmentNo;
data['AppointmentDate'] = this.appointmentDate;
data['AppointmentDateN'] = this.appointmentDateN;
data['ClinicID'] = this.clinicID;
data['DoctorID'] = this.doctorID;
data['InvoiceNo'] = this.invoiceNo;
data['Status'] = this.status;
data['ArrivedOn'] = this.arrivedOn;
data['DoctorName'] = this.doctorName;
data['DoctorNameN'] = this.doctorNameN;
data['DisplayInvoiceNo'] = this.displayInvoiceNo;
data['ClinicName'] = this.clinicName;
data['DecimalDoctorRate'] = this.decimalDoctorRate;
data['DoctorImageURL'] = this.doctorImageURL;
data['DoctorRate'] = this.doctorRate;
data['PatientNumber'] = this.patientNumber;
data['ProjectName'] = this.projectName;
return data;
}
}

@ -5,16 +5,21 @@ import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoice_details_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_pharmacy_invoices_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class MyInvoicesRepo {
Future<Either<Failure, GenericApiModel<List<GetInvoicesListResponseModel>>>> getAllInvoicesList();
Future<Either<Failure, GenericApiModel<List<GetPharmacyInvoicesResponseModel>>>> getAllPharmacyInvoices();
Future<Either<Failure, GenericApiModel<GetInvoiceDetailsResponseModel>>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> sendInvoiceEmail({required num appointmentNo, required int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> downloadInvoice({required String setupId, required int invoiceNo, required int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> downloadPharmacyInvoice({required String setupId, required int invoiceNo, required int projectID});
}
class MyInvoicesRepoImp implements MyInvoicesRepo {
@ -61,6 +66,47 @@ class MyInvoicesRepoImp implements MyInvoicesRepo {
}
}
@override
Future<Either<Failure, GenericApiModel<List<GetPharmacyInvoicesResponseModel>>>> getAllPharmacyInvoices() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List<GetPharmacyInvoicesResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_ALL_PHARMACY_INVOICES,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['List_AllPharmacyInvoices'] ?? response['PharmacyInvoicesList'] ?? [];
final invoicesList = list
.map((item) => GetPharmacyInvoicesResponseModel.fromJson(item as Map<String, dynamic>))
.toList()
.cast<GetPharmacyInvoicesResponseModel>();
apiResponse = GenericApiModel<List<GetPharmacyInvoicesResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: invoicesList,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<GetInvoiceDetailsResponseModel>>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID}) async {
Map<String, dynamic> mapDevice = {
@ -178,4 +224,42 @@ class MyInvoicesRepoImp implements MyInvoicesRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel>> downloadPharmacyInvoice({required String setupId, required int invoiceNo, required int projectID}) async {
Map<String, dynamic> mapDevice = {
"SetupID": setupId,
"ProjectID": projectID,
"InvoiceNo": invoiceNo,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
DOWNLOAD_PHARMACY_INVOICE_PDF,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
apiResponse = GenericApiModel(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response["InvoiceReportPDFContent"],
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -3,6 +3,7 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoice_details_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_pharmacy_invoices_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -12,6 +13,7 @@ enum InvoiceFilterType { all, hospital, clinic, doctor }
class MyInvoicesViewModel extends ChangeNotifier {
bool isInvoicesListLoading = false;
bool isInvoiceDetailsLoading = false;
bool isPharmacyInvoicesLoading = false;
MyInvoicesRepo myInvoicesRepo;
ErrorHandlerService errorHandlerService;
@ -19,6 +21,8 @@ class MyInvoicesViewModel extends ChangeNotifier {
List<GetInvoicesListResponseModel> allInvoicesList = [];
List<GetInvoicesListResponseModel> _originalInvoicesList = [];
List<GetPharmacyInvoicesResponseModel> allPharmacyInvoicesList = [];
List<GetPharmacyInvoicesResponseModel> _originalPharmacyInvoicesList = [];
InvoiceFilterType currentFilter = InvoiceFilterType.all;
late GetInvoiceDetailsResponseModel invoiceDetailsResponseModel;
@ -29,6 +33,7 @@ class MyInvoicesViewModel extends ChangeNotifier {
String? selectedFilterItem;
String? downloadInvoicePDFBase64 = "";
String? downloadPharmacyInvoicePDFBase64 = "";
int selectedTabIndex = 0;
@ -36,9 +41,12 @@ class MyInvoicesViewModel extends ChangeNotifier {
setInvoicesListLoading() {
isInvoicesListLoading = true;
isPharmacyInvoicesLoading = true;
allInvoicesList.clear();
allPharmacyInvoicesList.clear();
_originalInvoicesList.clear();
currentFilter = InvoiceFilterType.all;
onTabChanged(0);
notifyListeners();
}
@ -79,6 +87,40 @@ class MyInvoicesViewModel extends ChangeNotifier {
);
}
Future<void> getAllPharmacyInvoices({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isPharmacyInvoicesLoading = true;
allPharmacyInvoicesList.clear();
notifyListeners();
final result = await myInvoicesRepo.getAllPharmacyInvoices();
result.fold(
(failure) async {
isPharmacyInvoicesLoading = false;
notifyListeners();
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
_originalPharmacyInvoicesList = [];
allPharmacyInvoicesList = [];
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
_originalPharmacyInvoicesList = apiResponse.data ?? [];
_originalPharmacyInvoicesList.sort((a, b) => (b.appointmentDate ?? '').compareTo(a.appointmentDate ?? ''));
allPharmacyInvoicesList = List.from(_originalPharmacyInvoicesList);
isPharmacyInvoicesLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.getInvoiceDetails(appointmentNo: appointmentNo, invoiceNo: invoiceNo, projectID: projectID);
result.fold(
@ -151,6 +193,32 @@ class MyInvoicesViewModel extends ChangeNotifier {
);
}
Future<void> downloadPharmacyInvoicePDF({required String setupId, required int invoiceNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.downloadPharmacyInvoice(setupId: setupId, invoiceNo: invoiceNo, projectID: projectID);
result.fold(
(failure) async {
if (onError != null) {
onError(failure.message);
}
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data != null && apiResponse.data!.isNotEmpty) {
downloadPharmacyInvoicePDFBase64 = apiResponse.data!;
} else {
downloadPharmacyInvoicePDFBase64 = "";
}
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
void filterInvoices(InvoiceFilterType filterType) {
currentFilter = filterType;

@ -584,7 +584,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
)
: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.bgRedLightColor,
// color: AppColors.bgRedLightColor,
borderRadius: 12.r,
hasShadow: false,
),

@ -5,22 +5,18 @@ import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/my_invoices_details_page.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/invoice_filter_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/invoice_list_card.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/pharmacy_invoice_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:open_filex/open_filex.dart';
import 'package:provider/provider.dart';
@ -135,6 +131,10 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
],
onTabChange: (index) {
myInvoicesVM.onTabChanged(index);
if (index == 1 && myInvoicesVM.allPharmacyInvoicesList.isEmpty) {
// Load pharmacy invoices when pharmacy tab is selected and list is empty
myInvoicesVM.getAllPharmacyInvoices();
}
},
).paddingSymmetrical(24.h, 0.h),
myInvoicesVM.selectedTabIndex == 0 ? Column(
@ -148,7 +148,7 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
myInvoicesViewModel.filterInvoices(InvoiceFilterType.all);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.all ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w600,
@ -164,7 +164,7 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
_showHospitalFilterBottomSheet(context);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.hospital ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w600,
@ -180,7 +180,7 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
_showClinicFilterBottomSheet(context);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.clinic ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w600,
@ -196,7 +196,7 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
_showDoctorFilterBottomSheet(context);
},
backgroundColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.bgRedLightColor : AppColors.whiteColor,
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
borderColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.2),
textColor: myInvoicesVM.currentFilter == InvoiceFilterType.doctor ? AppColors.primaryRedColor : AppColors.blackColor,
fontSize: 12,
fontWeight: FontWeight.w600,
@ -329,7 +329,93 @@ class _MyInvoicesListState extends State<MyInvoicesList> {
: Utils.getNoDataWidget(context);
}).paddingSymmetrical(24.w, 0.h),
],
) : Container(),
)
: Column(
children: [
SizedBox(height: 16.h),
ListView.builder(
itemCount: myInvoicesVM.isPharmacyInvoicesLoading
? 4
: myInvoicesVM.allPharmacyInvoicesList.isEmpty
? 1
: myInvoicesVM.allPharmacyInvoicesList.length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsetsGeometry.zero,
itemBuilder: (context, index) {
return myInvoicesVM.isPharmacyInvoicesLoading
? LabResultItemView(onTap: () {}, labOrder: null, index: index, isLoading: true)
: myInvoicesVM.allPharmacyInvoicesList.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
child: PharmacyInvoiceCard(
pharmacyInvoice: myInvoicesVM.allPharmacyInvoicesList[index],
onTap: () async {
// if (Utils.isVidaPlusProject(myInvoicesVM.allPharmacyInvoicesList[index].projectID ?? 0)) {
// // For Vida+ projects, send email (if API is available)
// showCommonBottomSheetWithoutHeight(
// context,
// child: Utils.getSuccessWidget(
// loadingText: LocaleKeys.comingSoon.tr(context: context),
// ),
// callBackFunc: () {},
// isFullScreen: false,
// isCloseButtonVisible: true,
// isAutoDismiss: true,
// );
// } else {
// Download pharmacy invoice PDF
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.loadingText.tr(context: context));
myInvoicesViewModel.downloadPharmacyInvoicePDF(
setupId: myInvoicesVM.allPharmacyInvoicesList[index].setupId ?? "",
invoiceNo: myInvoicesVM.allPharmacyInvoicesList[index].invoiceNo ?? 0,
projectID: myInvoicesVM.allPharmacyInvoicesList[index].projectID ?? 0,
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onSuccess: (value) async {
LoaderBottomSheet.hideLoader();
if (myInvoicesViewModel.downloadPharmacyInvoicePDFBase64!.isNotEmpty) {
String path = await Utils.createFileFromString(myInvoicesViewModel.downloadPharmacyInvoicePDFBase64!, "pdf");
try {
OpenFilex.open(path);
} catch (ex) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Cannot open file"),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
}
},
);
// }
},
),
),
),
),
)
: Utils.getNoDataWidget(context);
}).paddingSymmetrical(24.w, 0.h),
],
),
],
);
}),

@ -0,0 +1,186 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_pharmacy_invoices_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'dart:ui' as ui;
class PharmacyInvoiceCard extends StatelessWidget {
final GetPharmacyInvoicesResponseModel pharmacyInvoice;
final VoidCallback onTap;
const PharmacyInvoiceCard({
super.key,
required this.pharmacyInvoice,
required this.onTap,
});
@override
Widget build(BuildContext context) {
final isArabic = getIt<AppState>().isArabic();
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(14.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Type chips
// Wrap(
// alignment: WrapAlignment.start,
// direction: Axis.horizontal,
// spacing: 6.w,
// runSpacing: 6.h,
// children: [
// AppCustomChipWidget(
// icon: AppAssets.pharmacy_icon,
// iconColor: AppColors.primaryRedColor,
// labelText: LocaleKeys.pharmacy.tr(context: context),
// textColor: AppColors.primaryRedColor,
// ),
// if (pharmacyInvoice.totalAmount != null)
// AppCustomChipWidget(
// labelText: '${pharmacyInvoice.totalAmount!.toStringAsFixed(2)} ${LocaleKeys.sar.tr(context: context)}',
// backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
// textColor: AppColors.primaryRedColor,
// isEnglishOnly: true,
// ),
// ],
// ),
SizedBox(height: 16.h),
// Main content row
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Image.network(
pharmacyInvoice.doctorImageURL ?? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png',
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
).circle(100.r),
Transform.translate(
offset: Offset(0.0, -20.h),
child: Container(
width: 40.w,
height: 40.h,
decoration: BoxDecoration(
color: AppColors.whiteColor,
shape: BoxShape.circle,
border: Border.all(
color: AppColors.scaffoldBgColor,
width: 1.5.w,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h, applyThemeColor: false),
SizedBox(height: 2.h),
"${pharmacyInvoice.decimalDoctorRate ?? '0.0'}".toText11(isBold: true, color: AppColors.textColor),
],
),
).circle(100),
),
],
),
SizedBox(width: 16.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(getIt<AppState>().isArabic()
? (pharmacyInvoice.doctorNameN ?? pharmacyInvoice.doctorName ?? LocaleKeys.doctor.tr(context: context))
: (pharmacyInvoice.doctorName ?? pharmacyInvoice.doctorNameN ?? LocaleKeys.doctor.tr(context: context))
).toText16(isBold: true),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 6.w,
runSpacing: 6.h,
children: [
AppCustomChipWidget(
labelText: "${LocaleKeys.invoiceNo.tr(context: context)}: ${pharmacyInvoice.invoiceNo ?? '-'}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
isEnglishOnly: true,
),
AppCustomChipWidget(
labelText: ((pharmacyInvoice.clinicName ?? LocaleKeys.clinic.tr(context: context)).length > 15
? '${(pharmacyInvoice.clinicName ?? LocaleKeys.clinic.tr(context: context)).substring(0, 12)}...'
: (pharmacyInvoice.clinicName ?? LocaleKeys.clinic.tr(context: context))),
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
),
AppCustomChipWidget(
labelText: pharmacyInvoice.projectName ?? LocaleKeys.hospital.tr(context: context),
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
if (pharmacyInvoice.appointmentDate != null)
Directionality(
textDirection: ui.TextDirection.ltr,
child: AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
icon: AppAssets.doctor_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(pharmacyInvoice.appointmentDate), false),
isEnglishOnly: true,
),
),
],
),
],
),
),
],
),
SizedBox(height: 16.h),
// Action button
CustomButton(
text: Utils.isVidaPlusProject(pharmacyInvoice.projectID ?? 0)
? LocaleKeys.sendEmail.tr(context: context)
: LocaleKeys.downloadInvoice.tr(context: context),
onPressed: onTap,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
borderColor: AppColors.primaryRedColor.withValues(alpha: 0.01),
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
iconSize: 14.h,
),
],
),
),
).paddingOnly(bottom: 16.h);
}
String _formatDate(String? dateString) {
if (dateString == null || dateString.isEmpty) return '-';
try {
final date = DateUtil.convertStringToDate(dateString);
return DateUtil.formatDateToDate(date, false);
} catch (e) {
return dateString;
}
}
}
Loading…
Cancel
Save