dev_sultan #56

Merged
Haroon6138 merged 15 commits from dev_sultan into master 1 month ago

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 161 KiB

@ -0,0 +1,3 @@
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.5525 2.46209C9.79631 1.38751 8.20843 1.81413 7.24747 2.53374L7.24696 2.53412L6.99967 2.71856L6.75249 2.53412C5.79154 1.81445 4.20322 1.38747 2.44697 2.46209C1.21445 3.21625 0.537796 4.77917 0.775779 6.54921C1.01526 8.33035 2.16771 10.3232 4.57364 12.0996L4.64687 12.1537C5.46216 12.7562 6.04566 13.1875 6.99985 13.1875C7.95405 13.1875 8.53754 12.7562 9.35283 12.1537L9.42606 12.0996C10.3581 11.4114 11.1012 10.6918 11.6765 9.96419C11.6797 9.96013 11.6828 9.95603 11.6859 9.95191C14.0531 6.94717 13.5653 3.69371 11.5525 2.46209ZM7.74698 6.53198L10.4778 9.62245C10.0168 10.1444 9.44544 10.6701 8.74767 11.1853C7.83876 11.8564 7.54669 12.05 6.99985 12.05C6.45302 12.05 6.16095 11.8564 5.25204 11.1853C3.02962 9.54441 2.09491 7.80338 1.90596 6.39801C1.71551 4.98153 2.26916 3.90531 3.0432 3.43169C4.33507 2.64121 5.40954 2.95773 6.05358 3.43314L4.70267 4.46071C3.88293 5.08424 3.8086 6.28812 4.54542 7.00729C4.86355 7.31779 5.27961 7.48142 5.70118 7.48816C5.71901 7.48845 5.73685 7.48845 5.75469 7.48818C6.05478 7.48357 6.3557 7.39938 6.62418 7.232L7.74698 6.53198Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -126,7 +126,7 @@
"gregorianDate": "التاريخ الميلادي",
"verifyLoginWith": "يرجى اختيار واحدة من الخيارات التالية للتحقق",
"registerUser": "تسجيل",
"verifyWithFingerprint": "بصمة الإصبع",
"verifyWithFingerprint":"البيومترية",
"verifyWithFaceid": "معرف الوجه",
"verifyWithSms": "رسالة قصيرة",
"verifyWithWhatsapp": "واتساب",

@ -126,7 +126,7 @@
"gregorianDate": "Gregorian Date",
"verifyLoginWith": "Please choose one of the following options to verify",
"registerUser": "Register",
"verifyWithFingerprint": "Fingerprint",
"verifyWithFingerprint": "Biometric",
"verifyWithFaceid": "Face ID",
"verifyWithSms": "SMS",
"verifyWithWhatsapp": "Whatsapp",
@ -561,12 +561,12 @@
"selectTamaraPlan": "Select Tamara Payment Plan",
"changeMethod": "Change Method",
"reviewOrder": "Review Order",
"active": "ACTIVE",
"inactive": "INACTIVE",
"balance": "BALANCE",
"active": "Active",
"inactive": "InActive",
"balance": "Balance",
"gained": "GAINED",
"consumed": "Consumed",
"transferred": "TRANSFERRED",
"transferred": "Transferred",
"riyal": "RIYAL",
"membersince": "MEMBER SINCE",
"identification": "رقم الهوية",

@ -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.uat;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
@ -803,6 +807,8 @@ class ApiConsts {
static final String getPrivileges = 'Services/Patients.svc/REST/Service_Privilege';
static final String registerUser = 'Services/Authentication.svc/REST/PatientRegistration';
static final String addFamilyFile = 'Services/Patients.svc/REST/ShareFamilyFileService';
// static values for Api
static final double appVersionID = 18.7;
static final int appChannelId = 3;

@ -143,12 +143,15 @@ class AppAssets {
static const String closeBottomNav = '$svgBasePath/close_bottom_nav.svg';
static const String feedback = '$svgBasePath/feedback.svg';
static const String news = '$svgBasePath/news.svg';
static const String heart = '$svgBasePath/heart.svg';
// PNGS //
static const String hmg_logo = '$pngBasePath/hmg_logo.png';
static const String livecare_service = '$pngBasePath/livecare_service.png';
static const String male_img = '$pngBasePath/male_img.png';
static const String femaleImg = '$pngBasePath/female_img.png';
static const String babyGirlImg = '$pngBasePath/baby_girl_img.png';
static const String babyBoyImg = '$pngBasePath/baby_img.png';
static const String apple_pay = '$pngBasePath/Apple_Pay.png';
static const String mada = '$pngBasePath/Mada.png';
static const String Mastercard = '$pngBasePath/Mastercard.png';

@ -8,22 +8,9 @@
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
enum AuthMethodTypesEnum {
sms,
whatsApp,
fingerPrint,
faceID,
moreOptions,
}
enum AuthMethodTypesEnum { sms, whatsApp, fingerPrint, faceID, moreOptions }
enum ViewStateEnum {
hide,
idle,
busy,
error,
busyLocal,
errorLocal,
}
enum ViewStateEnum { hide, idle, busy, error, busyLocal, errorLocal }
enum CountryEnum { saudiArabia, unitedArabEmirates }
@ -35,7 +22,7 @@ enum GenderTypeEnum { male, female }
enum MaritalStatusTypeEnum { single, married, divorced, widowed }
enum ChipTypeEnum { success, error, alert, info, warning }
enum ChipTypeEnum { success, error, alert, info, warning, lightBg, primaryRed }
enum OTPTypeEnum { sms, whatsapp, faceIDFingerprint }

@ -8,16 +8,9 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:huawei_location/huawei_location.dart' as HmsLocation
show
FusedLocationProviderClient,
Location,
LocationSettingsRequest,
LocationRequest;
import 'package:location/location.dart'
show Location, PermissionStatus, LocationData;
import 'package:permission_handler/permission_handler.dart'
show Permission, PermissionListActions, PermissionStatusGetters;
import 'package:huawei_location/huawei_location.dart' as HmsLocation show FusedLocationProviderClient, Location, LocationSettingsRequest, LocationRequest;
import 'package:location/location.dart' show Location, PermissionStatus, LocationData;
import 'package:permission_handler/permission_handler.dart' show Permission, PermissionListActions, PermissionStatusGetters;
class LocationUtils {
NavigationService navigationService;
@ -39,8 +32,7 @@ class LocationUtils {
isGMSDevice = GmsCheck().checkGmsAvailability();
}
void getLocation(
{Function(LatLng)? onSuccess, VoidCallback? onFailure}) async {
void getLocation({Function(LatLng)? onSuccess, VoidCallback? onFailure}) async {
if (Platform.isIOS) {
getCurrentLocation(onFailure: onFailure, onSuccess: onSuccess);
return;
@ -54,8 +46,7 @@ class LocationUtils {
getHMSLocation(onFailure: onFailure, onSuccess: onSuccess);
}
void getCurrentLocation(
{Function(LatLng)? onSuccess, VoidCallback? onFailure}) async {
void getCurrentLocation({Function(LatLng)? onSuccess, VoidCallback? onFailure}) async {
var location = Location();
bool isLocationEnabled = await location.serviceEnabled();
@ -72,8 +63,7 @@ class LocationUtils {
LocationPermission permissionGranted = await Geolocator.checkPermission();
if (permissionGranted == LocationPermission.denied) {
permissionGranted = await Geolocator.requestPermission();
if (permissionGranted != LocationPermission.whileInUse &&
permissionGranted != LocationPermission.always) {
if (permissionGranted != LocationPermission.whileInUse && permissionGranted != LocationPermission.always) {
appState.resetLocation();
onFailure?.call();
return;
@ -82,13 +72,11 @@ class LocationUtils {
Position? currentLocation = await Geolocator.getLastKnownPosition();
if(currentLocation?.latitude == null || currentLocation?.longitude == null){
currentLocation = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.low);
if (currentLocation?.latitude == null || currentLocation?.longitude == null) {
currentLocation = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.low);
}
LatLng locationData = LatLng(
currentLocation?.latitude ?? 0.0, currentLocation?.longitude ?? 0.0);
LatLng locationData = LatLng(currentLocation?.latitude ?? 0.0, currentLocation?.longitude ?? 0.0);
saveLatLngToAppState(locationData);
onSuccess?.call(locationData);
}
@ -197,22 +185,17 @@ class LocationUtils {
appState.userLong = locationData.longitude;
}
void getHMSLocation(
{VoidCallback? onFailure, Function(LatLng p1)? onSuccess}) async {
void getHMSLocation({VoidCallback? onFailure, Function(LatLng p1)? onSuccess}) async {
try {
var location = Location();
HmsLocation.FusedLocationProviderClient locationService =
HmsLocation.FusedLocationProviderClient()..initFusedLocationService();
HmsLocation.FusedLocationProviderClient locationService = HmsLocation.FusedLocationProviderClient()..initFusedLocationService();
bool isLocationEnabled = await Geolocator.isLocationServiceEnabled();
//if the location service is not enabled, ask the user to enable it
if (!isLocationEnabled) {
HmsLocation.LocationRequest locationRequest =
HmsLocation.LocationRequest()
..priority = HmsLocation.LocationRequest.PRIORITY_HIGH_ACCURACY;
HmsLocation.LocationRequest locationRequest = HmsLocation.LocationRequest()..priority = HmsLocation.LocationRequest.PRIORITY_HIGH_ACCURACY;
HmsLocation.LocationSettingsRequest request =
HmsLocation.LocationSettingsRequest(
HmsLocation.LocationSettingsRequest request = HmsLocation.LocationSettingsRequest(
alwaysShow: true,
needBle: false,
requests: [locationRequest],
@ -223,8 +206,7 @@ class LocationUtils {
LocationPermission permissionGranted = await Geolocator.checkPermission();
if (permissionGranted == LocationPermission.denied) {
permissionGranted = await Geolocator.requestPermission();
if (permissionGranted != LocationPermission.whileInUse &&
permissionGranted != LocationPermission.always) {
if (permissionGranted != LocationPermission.whileInUse && permissionGranted != LocationPermission.always) {
appState.resetLocation();
onFailure?.call();
return;
@ -246,8 +228,7 @@ class LocationUtils {
onFailure?.call();
return;
}
var locationData =
LatLng(data.latitude ?? 0.0, data.longitude ?? 0.0);
var locationData = LatLng(data.latitude ?? 0.0, data.longitude ?? 0.0);
saveLatLngToAppState(locationData);
onSuccess?.call(locationData);
});

@ -246,4 +246,20 @@ class RequestUtils {
if (!isDubai) "HealthId": appState.getNHICUserData.healthId,
};
}
static dynamic getAddFamilyRequest({required String nationalIDorFile, required String mobileNo, required String countryCode, required int loginType}) {
var request = <String, dynamic>{};
if (loginType == 1) {
request["sharedPatientID"] = 0;
request["sharedPatientIdentificationID"] = nationalIDorFile;
} else if (loginType == 2) {
request["sharedPatientID"] = int.parse(nationalIDorFile);
request["sharedPatientIdentificationID"] = '';
}
request["searchType"] = loginType;
request["sharedPatientMobileNumber"] = mobileNo;
request["zipCode"] = countryCode;
request["isRegister"] = false;
request["patientStatus"] = 2;
}
}

@ -606,6 +606,27 @@ class Utils {
);
}
static Widget buildImgWithAssets({
required String icon,
Color? iconColor,
bool isDisabled = false,
double width = 24,
double height = 24,
BoxFit fit = BoxFit.cover,
}) {
return Image.asset(icon, width: width, height: height, fit: fit);
}
/// Widget to build an SVG from network
static Widget buildImgWithNetwork({required String url, required Color iconColor, bool isDisabled = false, double width = 24, double height = 24, BoxFit fit = BoxFit.cover}) {
return Image.network(
url,
width: width,
height: height,
fit: fit,
);
}
static Widget getPaymentMethods() {
return Row(
mainAxisSize: MainAxisSize.max,

@ -140,4 +140,34 @@ class ValidationUtils {
return true;
}
static bool isValidatedIdAndPhoneWithCountryValidation({String? nationalId, String? phoneNumber, required Function() onOkPress, CountryEnum? selectedCountry}) {
bool isCorrectID = true;
if (nationalId == null || nationalId.isEmpty) {
_dialogService.showExceptionBottomSheet(message: LocaleKeys.pleaseEnterAnationalID.tr(), onOkPressed: onOkPress);
isCorrectID = false;
}
if (nationalId != null && nationalId.isNotEmpty && selectedCountry != null) {
if (selectedCountry == CountryEnum.saudiArabia) {
if (!validateIqama(nationalId)) {
_dialogService.showExceptionBottomSheet(message: LocaleKeys.pleaseEnterAValidIqamaID.tr(), onOkPressed: onOkPress);
return false;
}
}
if (selectedCountry == CountryEnum.unitedArabEmirates) {
if (!validateUaeNationalId(nationalId)) {
_dialogService.showExceptionBottomSheet(message: LocaleKeys.pleaseEnterAValidNationalID.tr(), onOkPressed: onOkPress);
return false;
}
}
if (phoneNumber == null || phoneNumber.isEmpty) {
_dialogService.showExceptionBottomSheet(message: LocaleKeys.enterValidPhoneNumber.tr(), onOkPressed: onOkPress);
return false;
}
}
return isCorrectID;
}
}

@ -233,6 +233,10 @@ extension ChipTypeEnumExtension on ChipTypeEnum {
return AppColors.infoColor; // Replace with your actual color
case ChipTypeEnum.warning:
return AppColors.warningColor; // Replace with your actual color
case ChipTypeEnum.lightBg:
return AppColors.chipPrimaryRedBorderColor; // Replace with your actual color
case ChipTypeEnum.primaryRed:
return AppColors.chipSecondaryLightRedColor; // Replace with your actual color
}
}
@ -248,6 +252,10 @@ extension ChipTypeEnumExtension on ChipTypeEnum {
return AppColors.infoLightColor; // Replace with your actual color
case ChipTypeEnum.warning:
return AppColors.warningLightColor; // Replace with your actual color
case ChipTypeEnum.lightBg:
return AppColors.chipSecondaryLightRedColor; // Replace with your actual color
case ChipTypeEnum.primaryRed:
return AppColors.chipPrimaryRedBorderColor;
}
}
}

@ -17,6 +17,8 @@ class LabViewModel extends ChangeNotifier {
List<String> get labSuggestions => _labSuggestionsList;
Set<TestDetails> uniqueTests = {};
LabViewModel({required this.labRepo, required this.errorHandlerService});
initLabProvider() {
@ -32,8 +34,8 @@ class LabViewModel extends ChangeNotifier {
final result = await labRepo.getPatientLabOrders();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
@ -43,6 +45,7 @@ class LabViewModel extends ChangeNotifier {
isLabOrdersLoading = false;
isLabResultsLoading = false;
filterSuggestions();
getUniqueTestDescription();
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
@ -75,4 +78,15 @@ class LabViewModel extends ChangeNotifier {
}
notifyListeners();
}
getUniqueTestDescription() {
uniqueTests = {
for (var item in patientLabOrders)
if (item.testDetails != null)
...?item.testDetails?.map<TestDetails>((test) =>
TestDetails(description: test.description.toString(), testCode: test.testCode.toString(), testID: test.testID, createdOn: item.createdOn))
};
uniqueTests.forEach(print);
}
}

@ -226,13 +226,14 @@ class TestDetails {
String? description;
String? testCode;
String? testID;
TestDetails({this.description, this.testCode, this.testID});
String? createdOn;
TestDetails({this.description, this.testCode, this.testID, this.createdOn});
TestDetails.fromJson(Map<String, dynamic> json) {
description = json['Description'];
testCode = json['TestCode'];
testID = json['TestID'];
createdOn = json['CreatedOn'];
}
Map<String, dynamic> toJson() {
@ -240,6 +241,7 @@ class TestDetails {
data['Description'] = this.description;
data['TestCode'] = this.testCode;
data['TestID'] = this.testID;
data['CreatedOn'] = this.createdOn;
return data;
}
}

@ -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();
Future<Either<Failure, GenericApiModel<List<dynamic>>>> addFamilyFile({required dynamic request});
}
class MedicalFileRepoImp implements MedicalFileRepo {
@ -267,4 +272,80 @@ 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()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<dynamic>>>> addFamilyFile({dynamic request}) async {
try {
GenericApiModel<List<dynamic>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.addFamilyFile,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
print(response);
// final list = response['GetAllSharedRecordsByStatusList'];
//
// 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,14 @@
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/core/utils/request_utils.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,10 +30,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});
@ -217,4 +226,76 @@ 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);
}
}
},
);
}
Future<void> addFamilyFile() async {
final resultEither = await medicalFileRepo.addFamilyFile(request: {});
resultEither.fold((failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) async {});
}
}

@ -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,
};
}

@ -0,0 +1,84 @@
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_export.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.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/lab/models/resp_models/patient_lab_orders_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 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart';
class LabOrderByTest extends StatelessWidget {
final VoidCallback onTap;
final int index;
final TestDetails? tests;
final bool isLoading;
final bool isExpanded;
const LabOrderByTest({super.key, required this.onTap, this.tests, required this.index, this.isLoading = false, this.isExpanded = false});
@override
build(BuildContext context) {
return AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
margin: EdgeInsets.symmetric(vertical: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
child: InkWell(
onTap: () {
if (!isLoading) {
onTap();
}
},
child: Container(
key: ValueKey<int>(index),
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// ...labOrder!.testDetails!.map((detail) {
Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: '${tests!.description}'.toText14(weight: FontWeight.w500),
),
SizedBox(height: 12.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AppCustomChipWidget(
richText: '${"Last Tested:".needTranslation} ${ DateUtil.formatDateToDate(DateUtil.convertStringToDate(tests!.createdOn), false)}'.toText12(isBold: true),
// chipType: ChipTypeEnum.lightBg,
backgroundColor: AppColors.greyLightColor,
textColor: AppColors.textColor,
// borderRadius: 5,
),
CustomButton(
icon: AppAssets.view_report_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
text: LocaleKeys.viewReport.tr(context: context),
onPressed: () {},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontWeight: FontWeight.bold,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 40.h,
),
],
),
],
),
)));
}
}

@ -11,6 +11,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_order_by_test.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@ -32,7 +33,7 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
List<List<TestDetails>?> labSuggestions = [];
int? expandedIndex;
String? selectedFilterText = '';
int activeIndex = 0;
@override
void initState() {
scheduleMicrotask(() {
@ -78,7 +79,10 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
// CustomTabBarModel(null, "Completed".needTranslation),
],
onTabChange: (index) {
// myAppointmentsViewModel.onTabChange(index);
activeIndex = index;
setState(() {
});
},
),
SizedBox(height: 16.h),
@ -89,39 +93,73 @@ class _LabOrdersPageState extends State<LabOrdersPage> {
isSelected: true,
)
: SizedBox(),
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: model.isLabOrdersLoading ? 5 : model.patientLabOrders.length,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
? LabResultItemView(
activeIndex == 0
? ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: model.isLabOrdersLoading ? 5 : model.patientLabOrders.length,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabResultItemView(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
labOrder: model.patientLabOrders[index],
index: index,
isExpanded: isExpanded)),
),
);
},
)
: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: model.isLabOrdersLoading ? 5 :model.uniqueTests.toList().length,
itemBuilder: (context, index) {
final isExpanded = expandedIndex == index;
return model.isLabOrdersLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabResultItemView(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
labOrder: model.patientLabOrders[index],
index: index,
isExpanded: isExpanded)),
),
);
},
),
) : AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: LabOrderByTest(
onTap: () {
setState(() {
expandedIndex = isExpanded ? null : index;
});
},
tests: model.uniqueTests.toList()[index],
index: index,
isExpanded: isExpanded)),
),
);
},
)
],
);
},

@ -4,9 +4,11 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.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/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/request_utils.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';
@ -15,6 +17,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';
@ -33,7 +36,10 @@ import 'package:hmg_patient_app_new/presentation/medical_file/vaccine_list_page.
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/lab_rad_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_file_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/patient_sick_leave_card.dart';
import 'package:hmg_patient_app_new/presentation/my_family/my_Family.dart';
import 'package:hmg_patient_app_new/presentation/my_family/widget/my_family_sheet.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/services/navigation_service.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';
@ -72,6 +78,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
insuranceViewModel.initInsuranceProvider();
medicalFileViewModel.setIsPatientSickLeaveListLoading(true);
medicalFileViewModel.getPatientSickLeaveList();
medicalFileViewModel.getFamilyFiles();
medicalFileViewModel.onTabChanged(0);
}
});
@ -85,6 +92,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
appState = getIt.get<AppState>();
NavigationService navigationService = getIt.get<NavigationService>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
@ -111,10 +119,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
SizedBox(height: 16.h),
Container(
width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24,
),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
@ -123,11 +128,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(
appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg,
width: 56.h,
height: 56.h,
),
Image.asset(appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, width: 56.h, height: 56.h),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -768,4 +769,9 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
return Container();
}
}
getMember() {
// AuthanticationViewModel authanticationViewModel = getIt.get<AuthanticationViewModel>();
// RequestUtils.getAddFamilyRequest(nationalIDorFile: nationalIDorFile, mobileNo: mobileNo, countryCode: countryCode, loginType: loginType);
}
}

@ -0,0 +1,197 @@
import 'package:easy_localization/easy_localization.dart';
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/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/core/utils/validation_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/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/family_file_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/my_family/widget/family_cards.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.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/dropdown/country_dropdown_widget.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
class FamilyMedicalScreen extends StatefulWidget {
final List<FamilyFileResponseModelLists> profiles;
final Function(FamilyFileResponseModelLists) onSelect;
const FamilyMedicalScreen({
Key? key,
required this.profiles,
required this.onSelect,
}) : super(key: key);
@override
State<FamilyMedicalScreen> createState() => _FamilyMedicalScreenState();
}
class _FamilyMedicalScreenState extends State<FamilyMedicalScreen> {
List<CustomTabBarModel> tabs = [CustomTabBarModel("", LocaleKeys.medicalFile.tr()), CustomTabBarModel("", LocaleKeys.request.tr())];
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.scaffoldBgColor,
appBar: CustomAppBar(
onBackPressed: () {
Navigator.of(context).pop();
},
onLanguageChanged: (lang) {},
hideLogoAndLang: true,
),
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.myMedicalFile.tr().toText26(color: AppColors.textColor, weight: FontWeight.w600, letterSpacing: -2),
SizedBox(height: 25.h),
CustomTabBar(
tabs: tabs,
onTabChange: (int index) {},
),
SizedBox(height: 25.h),
FamilyCards(profiles: widget.profiles, onSelect: widget.onSelect, isShowDetails: true),
SizedBox(height: 20.h),
],
),
).paddingSymmetrical(20, 0),
bottomSheet: Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
customBorder: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
),
padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 20.h),
child: CustomButton(
text: "Add a new family member",
onPressed: () {
showModelSheet();
},
icon: AppAssets.add_icon,
height: 56.h,
fontWeight: FontWeight.w600,
)),
);
}
void showModelSheet() {
AuthenticationViewModel authVm = getIt.get<AuthenticationViewModel>();
return showCommonBottomSheetWithoutHeight(context,
title: "Add Family Member",
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Please fill the below field to add a new family member to your profile".toText16(color: AppColors.textColor, weight: FontWeight.w500),
SizedBox(height: 20.h),
Container(
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)),
padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
child: Column(
children: [
CustomCountryDropdown(
countryList: CountryEnum.values,
onCountryChange: authVm.onCountryChange,
).paddingOnly(top: 8.h, bottom: 16.h),
Divider(
height: 1.h,
color: AppColors.spacerLineColor,
),
TextInputWidget(
labelText: LocaleKeys.nationalIdNumber.tr(),
hintText: "xxxxxxxxx",
controller: authVm.nationalIdController,
// focusNode: _nationalIdFocusNode,
isEnable: true,
prefix: null,
isAllowRadius: true,
isBorderAllowed: false,
isAllowLeadingIcon: true,
autoFocus: true,
keyboardType: TextInputType.number,
padding: EdgeInsets.symmetric(vertical: 8.h),
leadingIcon: AppAssets.student_card,
).paddingOnly(top: 8.h, bottom: 8.h),
Divider(
height: 1.h,
color: AppColors.spacerLineColor,
),
TextInputWidget(
labelText: LocaleKeys.phoneNumber.tr(),
hintText: "574345434",
controller: authVm.phoneNumberController,
isEnable: true,
prefix: authVm.selectedCountrySignup.countryCode,
isAllowRadius: true,
isBorderAllowed: false,
isAllowLeadingIcon: true,
autoFocus: true,
keyboardType: TextInputType.number,
padding: EdgeInsets.symmetric(vertical: 8.h),
leadingIcon: AppAssets.smart_phone,
).paddingOnly(top: 8.h, bottom: 4),
//TextInputWidget(
// labelText: widget.isForEmail ? LocaleKeys.email.tr() : LocaleKeys.phoneNumber.tr(),
// hintText: widget.isForEmail ? "demo@gmail.com" : "5xxxxxxxx",
// controller: widget.textController!,
// focusNode: _textFieldFocusNode,
// autoFocus: widget.autoFocus,
// padding: EdgeInsets.all(8.h),
// keyboardType: widget.isForEmail ? TextInputType.emailAddress : TextInputType.number,
// onChange: (value) {
// if (widget.onChange != null) {
// widget.onChange!(value);
// }
// },
// onCountryChange: (value) {
// if (widget.onCountryChange != null) {
// widget.onCountryChange!(value);
// }
// },
// isEnable: true,
// isReadOnly: widget.isFromSavedLogin,
// prefix: widget.isForEmail ? null : widget.countryCode,
// isBorderAllowed: false,
// isAllowLeadingIcon: true,
// fontSize: 13.h,
// isCountryDropDown: widget.isEnableCountryDropdown,
// leadingIcon: widget.isForEmail ? AppAssets.email : AppAssets.smart_phone,
// )
],
),
),
SizedBox(height: 20.h),
CustomButton(
text: "Verify the member",
onPressed: () {
FocusScope.of(context).unfocus();
if (ValidationUtils.isValidatedIdAndPhoneWithCountryValidation(
nationalId: authVm.nationalIdController.text,
selectedCountry: authVm.selectedCountrySignup,
phoneNumber: authVm.phoneNumberController.text,
onOkPress: () {
Navigator.of(context).pop();
},
)) {}
},
icon: AppAssets.add_icon,
height: 56.h,
fontWeight: FontWeight.w600),
SizedBox(height: 20.h),
],
),
callBackFunc: () {});
}
}

@ -0,0 +1,116 @@
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_export.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/enums.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/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/custom_chip_widget.dart';
class FamilyCards extends StatefulWidget {
final List<FamilyFileResponseModelLists> profiles;
final Function(FamilyFileResponseModelLists) onSelect;
final bool isShowDetails;
final bool isBottomSheet;
const FamilyCards({super.key, required this.profiles, required this.onSelect, this.isShowDetails = false, this.isBottomSheet = false});
@override
State<FamilyCards> createState() => _FamilyCardsState();
}
class _FamilyCardsState extends State<FamilyCards> {
AppState appState = getIt<AppState>();
@override
Widget build(BuildContext context) {
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: widget.profiles.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10.h,
mainAxisSpacing: 10.h,
childAspectRatio: widget.isShowDetails ? 0.56.h : 0.74.h,
),
itemBuilder: (context, index) {
final profile = widget.profiles[index];
final isActive = (profile.responseId == appState
.getAuthenticatedUser()
?.patientId);
return Container(
padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 15.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24),
child: Opacity(
opacity: isActive ? 0.4 : 1.0, // Fade all content if active
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 5.h),
Utils.buildImgWithAssets(
icon: profile.gender == 1 ? ((profile.age ?? 0) < 7 ? AppAssets.babyBoyImg : AppAssets.male_img) : (profile.age! < 7 ? AppAssets.babyGirlImg : AppAssets.femaleImg),
width: 80.h,
height: 78.h),
SizedBox(height: 8.h),
(profile.patientName ?? "Unknown").toText16(isBold: false, isCenter: true, maxlines: 1, weight: FontWeight.w600),
SizedBox(height: 4.h),
CustomChipWidget(
chipType: ChipTypeEnum.alert,
backgroundColor: AppColors.lightGrayBGColor,
chipText: "Relation: ${profile.relationship ?? "N/A"}",
iconAsset: AppAssets.heart,
isShowBorder: false,
borderRadius: 8.h,
textColor: AppColors.textColor),
widget.isShowDetails ? SizedBox(height: 4.h) : SizedBox(),
widget.isShowDetails
? CustomChipWidget(
chipType: ChipTypeEnum.alert,
backgroundColor: AppColors.lightGrayBGColor,
chipText: "Age: ${profile.age ?? "N/A"} Years",
isShowBorder: false,
borderRadius: 8.h,
textColor: AppColors.textColor,
)
: SizedBox(),
widget.isShowDetails ? SizedBox(height: 8.h) : SizedBox(),
Spacer(),
if (isActive)
CustomButton(
height: 40.h,
onPressed: () {},
text: LocaleKeys.active.tr(),
backgroundColor: Colors.grey.shade200,
borderColor: Colors.grey.shade200,
textColor: AppColors.greyTextColor,
fontSize: 13.h,
).paddingOnly(top: 0, bottom: 0)
else
CustomButton(
height: 40.h,
onPressed: () => widget.onSelect(profile),
text: LocaleKeys.select.tr(),
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 13.h,
icon: widget.isBottomSheet ? null : AppAssets.heart,
iconColor: AppColors.primaryRedColor,
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 0),
).paddingOnly(top: 0, bottom: 0),
],
),
),
);
},
);
}
}

@ -0,0 +1,31 @@
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/presentation/my_family/my_Family.dart';
import 'package:hmg_patient_app_new/presentation/my_family/widget/family_cards.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
class MyFamilySheet {
static void show(BuildContext context, List<FamilyFileResponseModelLists> familyLists, Function(FamilyFileResponseModelLists) onSelect) {
return showCommonBottomSheetWithoutHeight(
context,
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: FamilyCards(
profiles: familyLists,
onSelect: (profile) {
Navigator.of(context).pop(); // Close the bottom sheet
onSelect(profile); // Call the onSelect callback
},
isBottomSheet: true),
callBackFunc: () {},
);
}
}

@ -36,13 +36,15 @@ class AppColors {
static const Color warningColorYellow = Color(0xFFF4A308);
static const Color blackBgColor = Color(0xFF2E3039);
static const blackColor = textColor;
static const inputLabelTextColor = Color(0xff898A8D);
static const greyTextColor = Color(0xFF8F9AA3);
static const Color inputLabelTextColor = Color(0xff898A8D);
static const Color greyTextColor = Color(0xFF8F9AA3);
static const Color lightGrayBGColor = Color(0x142E3039);
static const lightGreenColor = Color(0xFF0ccedde);
static const textGreenColor = Color(0xFF18C273);
static const Color ratingColorYellow = Color(0xFFFFAF15);
static const Color spacerLineColor = Color(0x2E30391A);
//Chips
static const Color successColor = Color(0xff18C273);
@ -51,6 +53,8 @@ class AppColors {
static const Color infoColor = Color(0xFF0B85F7);
static const Color warningColor = Color(0xFFFFCC00);
static const Color greyColor = Color(0xFFEFEFF0);
static const Color chipPrimaryRedBorderColor = Color(0xFFED1C2B);
static const Color chipSecondaryLightRedColor = Color(0xFFFEE9EA);
static const Color successLightColor = Color(0xFF18C273);
static const Color errorLightColor = Color(0xFFED1C2B);

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/enums.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';
@ -12,6 +13,10 @@ class CustomChipWidget extends StatelessWidget {
final bool isSelected;
final double borderRadius;
final EdgeInsetsGeometry padding;
final Color? backgroundColor;
final Color? textColor;
final Color? borderColor;
final bool isShowBorder;
const CustomChipWidget({
super.key,
@ -22,6 +27,10 @@ class CustomChipWidget extends StatelessWidget {
this.isSelected = false,
this.borderRadius = 12,
this.padding = const EdgeInsets.all(8),
this.backgroundColor,
this.textColor,
this.borderColor,
this.isShowBorder = false,
});
@override
@ -32,11 +41,13 @@ class CustomChipWidget extends StatelessWidget {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius),
color: isSelected ? chipType.color : chipType.backgroundColor,
border: Border.all(
color: chipType.color,
width: isSelected ? 0 : 1,
),
color: isSelected ? chipType.color : backgroundColor ?? chipType.backgroundColor,
border: isShowBorder
? Border.all(
color: chipType.color,
width: isSelected ? 0 : 1,
)
: null,
),
child: InkWell(
onTap: hasOnTap ? onTap : null,
@ -51,18 +62,9 @@ class CustomChipWidget extends StatelessWidget {
children: [
if (iconAsset != null) ...[
Utils.buildSvgWithAssets(icon: iconAsset!),
const SizedBox(width: 6),
SizedBox(width: 4.h),
],
Text(
chipText.toUpperCase(),
style: context.dynamicTextStyle(
fontWeight: FontWeight.w500,
fontSize: 14,
color: isSelected ? Colors.white : chipType.color,
letterSpacing: 0.1,
isLanguageSwitcher: true,
),
),
chipText.toText10(isBold: true, color: isSelected ? Colors.white : textColor ?? chipType.color, maxlines: 1, weight: FontWeight.w500, letterSpacing: -0.5),
],
),
),

@ -1,44 +0,0 @@
import 'package:flutter/material.dart';
class ProfileSelector extends StatelessWidget {
final List<Map<String, dynamic>> profiles;
final Function(Map<String, dynamic>) onSelect;
const ProfileSelector({
Key? key,
required this.profiles,
required this.onSelect,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return 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),
);
}).toList(),
);
}
}

@ -1,15 +0,0 @@
import 'package:flutter/material.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) {
showCommonBottomSheetWithoutHeight(
context,
title: 'Select Profile',
child: ProfileSelector(profiles: profiles, onSelect: (profile) {
Navigator.of(context).pop(); // Close the bottom sheet
onSelect(profile); // Call the onSelect callback
}), callBackFunc: () {},
);
}
}
Loading…
Cancel
Save