Merge remote-tracking branch 'refs/remotes/origin/dev_sultan' into dev_aamir

pull/76/head
aamir-csol 1 month ago
commit fd98ed6fc3

@ -720,10 +720,14 @@ const SAVE_SETTING = 'Services/Patients.svc/REST/UpdatePateintInfo';
const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_InsertUpdate';
//family Files
const FAMILY_FILES= 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatus';
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

@ -11,6 +11,7 @@ import 'package:hmg_patient_app_new/features/medical_file/models/patient_vaccine
import 'package:hmg_patient_app_new/services/logger_service.dart';
import '../authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'models/family_file_response_model.dart';
abstract class MedicalFileRepo {
Future<Either<Failure, GenericApiModel<List<PatientVaccineResponseModel>>>> getPatientVaccinesList();
@ -22,6 +23,10 @@ abstract class MedicalFileRepo {
Future<Either<Failure, GenericApiModel<List<PatientMedicalReportResponseModel>>>> getPatientMedicalReportsList();
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientMedicalReportPDF(PatientMedicalReportResponseModel patientMedicalReportResponseModel, AuthenticatedUser authenticatedUser);
Future<Either<Failure, GenericApiModel<List<FamilyFileResponseModelLists>>>> getPatientFamilyFiles();
}
class MedicalFileRepoImp implements MedicalFileRepo {
@ -267,4 +272,45 @@ class MedicalFileRepoImp implements MedicalFileRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<FamilyFileResponseModelLists>>>> getPatientFamilyFiles() async {
try {
GenericApiModel<List<FamilyFileResponseModelLists>>? apiResponse;
Failure? failure;
await apiClient.post(
FAMILY_FILES,
body: {"Status":3},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['GetAllSharedRecordsByStatusList'];
// if (list == null || list.isEmpty) {
// throw Exception("lab list is empty");
// }
final familyLists = list.map((item) => FamilyFileResponseModelLists.fromJson(item as Map<String, dynamic>)).toList().cast<FamilyFileResponseModelLists>();
apiResponse = GenericApiModel<List<FamilyFileResponseModelLists>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: familyLists,
);
} 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()));
}
}
}

@ -1,9 +1,13 @@
import 'package:flutter/material.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/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_repo.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_medical_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_vaccine_response_model.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class MedicalFileViewModel extends ChangeNotifier {
@ -25,11 +29,14 @@ class MedicalFileViewModel extends ChangeNotifier {
List<PatientMedicalReportResponseModel> patientMedicalReportReadyList = [];
List<PatientMedicalReportResponseModel> patientMedicalReportCancelledList = [];
List<FamilyFileResponseModelLists> patientFamilyFiles =[];
String patientSickLeavePDFBase64 = "";
String patientMedicalReportPDFBase64 = "";
int selectedMedicalReportsTabIndex = 0;
static final DialogService _dialogService = getIt.get<DialogService>();
AppState _appState = getIt<AppState>();
MedicalFileViewModel({required this.medicalFileRepo, required this.errorHandlerService});
initMedicalFileProvider() {
@ -217,4 +224,64 @@ class MedicalFileViewModel extends ChangeNotifier {
},
);
}
Future<void> getFamilyFiles({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await medicalFileRepo.getPatientFamilyFiles();
result.fold(
(failure) async => await errorHandlerService.handleError(
failure: failure,
onOkPressed: () {
onError!(failure.message);
},
),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
_dialogService.showErrorBottomSheet(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientFamilyFiles = apiResponse.data!;
patientFamilyFiles.insert(0,
FamilyFileResponseModelLists(patientId: _appState.getAuthenticatedUser()!.patientId, patientName: '${_appState.getAuthenticatedUser()!.firstName!} ${_appState.getAuthenticatedUser()!.lastName!}', isActive: true, gender:_appState.getAuthenticatedUser()!.gender!, responseId: _appState.getAuthenticatedUser()!.patientId ),
);
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> switchFamilyFiles({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await medicalFileRepo.getPatientFamilyFiles();
result.fold(
(failure) async => await errorHandlerService.handleError(
failure: failure,
onOkPressed: () {
onError!(failure.message);
},
),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
_dialogService.showErrorBottomSheet(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientFamilyFiles = apiResponse.data!;
patientFamilyFiles.insert(0,
FamilyFileResponseModelLists(patientId: _appState.getAuthenticatedUser()!.patientId, patientName: '${_appState.getAuthenticatedUser()!.firstName!} ${_appState.getAuthenticatedUser()!.lastName!}', isActive: true, gender:_appState.getAuthenticatedUser()!.gender!, responseId: _appState.getAuthenticatedUser()!.patientId ),
);
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -0,0 +1,105 @@
import 'dart:convert';
class FamilyFileResponseModelLists {
int? id;
int? patientId;
int? responseId;
dynamic relationshipId;
dynamic relationship;
dynamic relationshipN;
int? regionId;
int? familyRegionId;
int? status;
dynamic isActive;
String? editedOn;
String? createdOn;
int? age;
String? emaiLAddress;
int? gender;
String? genderDescription;
String? genderImage;
String? mobileNumber;
int? patientDataVerified;
String? patientIdenficationNumber;
String? patientName;
String? statusDescription;
FamilyFileResponseModelLists({
this.id,
this.patientId,
this.responseId,
this.relationshipId,
this.relationship,
this.relationshipN,
this.regionId,
this.familyRegionId,
this.status,
this.isActive,
this.editedOn,
this.createdOn,
this.age,
this.emaiLAddress,
this.gender,
this.genderDescription,
this.genderImage,
this.mobileNumber,
this.patientDataVerified,
this.patientIdenficationNumber,
this.patientName,
this.statusDescription,
});
factory FamilyFileResponseModelLists.fromRawJson(String str) => FamilyFileResponseModelLists.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory FamilyFileResponseModelLists.fromJson(Map<String, dynamic> json) => FamilyFileResponseModelLists(
id: json["ID"],
patientId: json["PatientID"],
responseId: json["ResponseID"],
relationshipId: json["RelationshipID"],
relationship: json["Relationship"],
relationshipN: json["RelationshipN"],
regionId: json["RegionID"],
familyRegionId: json["FamilyRegionID"],
status: json["Status"],
isActive: json["IsActive"],
editedOn: json["EditedOn"],
createdOn: json["CreatedOn"],
age: json["Age"],
emaiLAddress: json["EmaiLAddress"],
gender: json["Gender"],
genderDescription: json["GenderDescription"],
genderImage: json["GenderImage"],
mobileNumber: json["MobileNumber"],
patientDataVerified: json["PatientDataVerified"],
patientIdenficationNumber: json["PatientIdenficationNumber"],
patientName: json["PatientName"],
statusDescription: json["StatusDescription"],
);
Map<String, dynamic> toJson() => {
"ID": id,
"PatientID": patientId,
"ResponseID": responseId,
"RelationshipID": relationshipId,
"Relationship": relationship,
"RelationshipN": relationshipN,
"RegionID": regionId,
"FamilyRegionID": familyRegionId,
"Status": status,
"IsActive": isActive,
"EditedOn": editedOn,
"CreatedOn": createdOn,
"Age": age,
"EmaiLAddress": emaiLAddress,
"Gender": gender,
"GenderDescription": genderDescription,
"GenderImage": genderImage,
"MobileNumber": mobileNumber,
"PatientDataVerified": patientDataVerified,
"PatientIdenficationNumber": patientIdenficationNumber,
"PatientName": patientName,
"StatusDescription": statusDescription,
};
}

@ -15,6 +15,7 @@ import 'package:hmg_patient_app_new/features/book_appointments/book_appointments
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.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_appointments/my_appointments_view_model.dart';
@ -40,6 +41,7 @@ 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/input_widget.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/my_family/my_family_sheet.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
@ -139,7 +141,14 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
iconColor: AppColors.blackColor,
iconSize: 12.h,
text: "File no: ${appState.getAuthenticatedUser()!.patientId}",
onPressed: () {},
onPressed: () {
//need to remove from this call from here once the family icons will be added
MyFamilySheet.show(context,medicalFileViewModel.patientFamilyFiles , (profile){
});
},
backgroundColor: AppColors.greyColor,
borderColor: AppColors.greyColor,
textColor: AppColors.blackColor,

@ -1,8 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.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/medical_file/models/family_file_response_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
class ProfileSelector extends StatelessWidget {
final List<Map<String, dynamic>> profiles;
final Function(Map<String, dynamic>) onSelect;
final List<FamilyFileResponseModelLists> profiles;
final Function(FamilyFileResponseModelLists) onSelect;
const ProfileSelector({
Key? key,
@ -10,35 +20,118 @@ class ProfileSelector extends StatelessWidget {
required this.onSelect,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
final double screenHeight = MediaQuery.of(context).size.height;
int? activeProfileId = Utils.appState.getAuthenticatedUser()?.patientId;
return SizedBox(
height: screenHeight * 0.6,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// const Text(
// "Please select a profile",
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
// ),
// const SizedBox(height: 6),
// const Text(
// "Switch from the below list of medical file",
// style: TextStyle(fontSize: 14, color: Colors.grey),
// textAlign: TextAlign.center,
// ),
const SizedBox(height: 20),
// GridView inside scroll
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: profiles.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 0.75,
),
itemBuilder: (context, index) {
final profile = profiles[index];
final isActive =
(profile.responseId == activeProfileId);
return Container(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: isActive ? Colors.grey.shade100 : AppColors.whiteColor, // Lighter background for active
borderRadius: 24,
),
child: Opacity(
opacity: isActive ? 0.5 : 1.0, // Fade all content if active
child: Column(
mainAxisSize: MainAxisSize.min,
children: profiles.map((profile) {
return ListTile(
leading: CircleAvatar(
radius: 22,
backgroundImage: profile["GenderImage"] != null &&
profile["GenderImage"].toString().isNotEmpty
? NetworkImage(profile["GenderImage"])
: AssetImage(
profile["Gender"] == 1
? "assets/images/male.png"
: "assets/images/female.png")
as ImageProvider,
),
title: Text(
profile["PatientName"] ?? "Unknown",
style: const TextStyle(fontWeight: FontWeight.w600),
),
subtitle: Text(
profile["Relationship"] ?? "Self",
style: const TextStyle(color: Colors.grey),
),
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
onTap: () => onSelect(profile),
children: [
const SizedBox(height: 5),
Container(
height: 80,
width: 78,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: AssetImage(
profile.gender == 1
? AppAssets.male_img
: AppAssets.femaleImg,
),
fit: BoxFit.cover,
),
),
),
const SizedBox(height: 8),
(profile.patientName ?? "Unknown").toText14(
isBold: true,
maxlines: 1,
isCenter: true,
),
const SizedBox(height: 4),
Text(
"Relation: ${profile.relationship ?? "N/A"}",
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 5),
if (isActive)
CustomButton(
height: 36,
onPressed: (){}, // Disabled
text: 'Active',
backgroundColor: Colors.grey.shade200,
borderColor: Colors.grey.shade200,
textColor: AppColors.greyTextColor,
fontSize: 13,
).paddingOnly(top: 8, bottom: 4)
else
CustomButton(
height: 36,
onPressed: () => onSelect(profile),
text: 'Select',
backgroundColor: const Color(0xffFEE9EA),
borderColor: const Color(0xffFEE9EA),
textColor: const Color(0xffED1C2B),
fontSize: 13,
).paddingOnly(top: 8, bottom: 4),
],
),
),
);
}).toList(),
},
),
],
),
),
);
}
}

@ -1,12 +1,23 @@
import 'package:flutter/material.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/features/medical_file/models/family_file_response_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import '../common_bottom_sheet.dart';
import 'my_Family.dart';
class MyFamilySheet {
static void show(BuildContext context, List<Map<String, dynamic>> profiles, Function(Map<String, dynamic>) onSelect) {
static void show(BuildContext context, List<FamilyFileResponseModelLists> familyLists, Function(FamilyFileResponseModelLists) onSelect) {
showCommonBottomSheetWithoutHeight(
context,
title: 'Select Profile',
child: ProfileSelector(profiles: profiles, onSelect: (profile) {
titleWidget: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'Please select a profile'.toText21(isBold: true),
'switch from the below list of medical file'.toText16(weight: FontWeight.w100, color: AppColors.greyTextColor),
],),
child: ProfileSelector(profiles: familyLists, onSelect: (profile) {
Navigator.of(context).pop(); // Close the bottom sheet
onSelect(profile); // Call the onSelect callback
}), callBackFunc: () {},

Loading…
Cancel
Save