My appointments workflow updates

haroon_dev
haroon amjad 21 hours ago
parent 74b0c1a926
commit ec4fb71586

@ -100,6 +100,8 @@ abstract class MyAppointmentsRepo {
Future<Either<Failure, GenericApiModel<List<GetInvoicesListResponseModel>>>> getAppointmentInvoice(num appointmentNum);
Future<Either<Failure, GenericApiModel<AppointmentParkingQRResponseModel>>> getParkingQR(num appointmentNum, int projectID);
Future<Either<Failure, GenericApiModel<PatientAppointmentHistoryResponseModel>>> getAppointmentDetailsByAppointmentNumber(int appointmentID, int projectID, int clinicID);
}
class MyAppointmentsRepoImp implements MyAppointmentsRepo {
@ -1238,4 +1240,42 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<PatientAppointmentHistoryResponseModel>>> getAppointmentDetailsByAppointmentNumber(int appointmentID, int projectID, int clinicID) async {
Map<String, dynamic> mapDevice = {
"AppointmentNo": appointmentID,
"ProjectID": projectID,
"ClinicID":clinicID,
"IsActiveAppointment": true,
};
try {
GenericApiModel<PatientAppointmentHistoryResponseModel>? apiResponse;
Failure? failure;
await apiClient.post(GET_PATIENT_APPOINTMENT_HISTORY, onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
}, onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['AppoimentAllHistoryResultList'];
final appointmentDetails = PatientAppointmentHistoryResponseModel.fromJson(list[0]);
apiResponse = GenericApiModel<PatientAppointmentHistoryResponseModel>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: appointmentDetails,
);
} catch (e) {
failure = DataParsingFailure(e.toString());
}
}, body: mapDevice);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -113,6 +113,9 @@ class MyAppointmentsViewModel extends ChangeNotifier {
Uint8List? parkingQRImageBytes;
late PatientAppointmentHistoryResponseModel currentSelectedAppointmentDetails;
bool isAppointmentDetailsLoading = false;
MyAppointmentsViewModel({required this.myAppointmentsRepo, required this.errorHandlerService, required this.appState});
void onTabChange(int index) {
@ -1761,4 +1764,31 @@ class MyAppointmentsViewModel extends ChangeNotifier {
},
);
}
updateAppointmentDetailsPage() {
notifyListeners();
}
Future<void> getAppointmentDetailsByAppointmentNumber({required int projectID, required int appointmentNo, required int clinicId, Function(dynamic)? onSuccess, Function(String)? onError}) async {
isAppointmentDetailsLoading = true;
notifyListeners();
final result = await myAppointmentsRepo.getAppointmentDetailsByAppointmentNumber(appointmentNo, projectID, clinicId);
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
onError!(apiResponse.errorMessage!);
} else if (apiResponse.messageStatus == 1) {
currentSelectedAppointmentDetails = apiResponse.data!;
isAppointmentDetailsLoading = false;
if (onSuccess != null) {
onSuccess(apiResponse.data);
}
}
},
);
}
}

@ -57,6 +57,8 @@ class AppointmentType {
return AppColors.successColor;
case 90:
return AppColors.alertColor;
case 110:
return AppColors.primaryRedColor;
default:
return AppColors.successColor;
}
@ -76,6 +78,8 @@ class AppointmentType {
return AppColors.successColor;
case 90:
return AppColors.alertColor;
case 110:
return AppColors.primaryRedColor;
default:
return AppColors.successColor;
}
@ -95,6 +99,8 @@ class AppointmentType {
return LocaleKeys.confirmLiveCare.tr();
case 90:
return LocaleKeys.checkinOption.tr();
case 110:
return LocaleKeys.viewDetails.tr();
default:
return LocaleKeys.upcomingNoAction.tr();
}
@ -114,6 +120,8 @@ class AppointmentType {
return AppAssets.confirm_appointment_icon;
case 90:
return AppAssets.appointment_checkin_icon;
case 110:
return AppAssets.calendar;
default:
return AppAssets.checkmark_icon;
}

@ -61,9 +61,9 @@ import 'package:provider/provider.dart';
import '../medical_file/widgets/medical_file_card.dart';
class AppointmentDetailsPage extends StatefulWidget {
const AppointmentDetailsPage({super.key, required this.patientAppointmentHistoryResponseModel});
AppointmentDetailsPage({super.key, required this.patientAppointmentHistoryResponseModel});
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
@override
State<AppointmentDetailsPage> createState() => _AppointmentDetailsPageState();
@ -103,6 +103,17 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo);
} else {
if (widget.patientAppointmentHistoryResponseModel.nextAction == 110) {
myAppointmentsViewModel
.getAppointmentDetailsByAppointmentNumber(
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo,
clinicId: widget.patientAppointmentHistoryResponseModel.clinicID)
.then((val) {
widget.patientAppointmentHistoryResponseModel = myAppointmentsViewModel.currentSelectedAppointmentDetails;
myAppointmentsViewModel.updateAppointmentDetailsPage();
});
}
Duration difference = DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate).difference(DateTime.now());
if (difference.inMinutes > 240) {
isAppointmentWithin4Hours = false;
@ -1043,8 +1054,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 ||
widget.patientAppointmentHistoryResponseModel.nextAction == 20)
if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || widget.patientAppointmentHistoryResponseModel.nextAction == 20)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -1052,10 +1062,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.amountBeforeTax.tr(context: context).toText18(isBold: true),
Utils.getPaymentAmountWithSymbol(
widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true),
AppColors.blackColor,
13,
Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: true),
],
),
@ -1063,10 +1070,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor)),
"VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})"
.toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -0.64),
Expanded(child: LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor)),
"VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})".toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -0.64),
],
),
SizedBox(height: 18.h),
@ -1077,10 +1082,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Utils.getPaymentAmountWithSymbol(
widget.patientAppointmentHistoryResponseModel.patientShareWithTax!.toString().toText24(isBold: true),
AppColors.blackColor,
17,
Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShareWithTax!.toString().toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: true),
],
),
@ -1118,8 +1120,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction);
},
backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction)
.withValues(alpha: 0.01),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01),
textColor: widget.patientAppointmentHistoryResponseModel.nextAction == 15 ? AppColors.textColor : Colors.white,
fontSize: 16.f,
fontWeight: FontWeight.w600,
@ -1132,7 +1133,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
).paddingSymmetrical(16.h, 24.h),
],
),
),
).toShimmer2(isShow: myAppointmentsViewModel.isAppointmentDetailsLoading),
),
],
),

@ -729,6 +729,7 @@ class _AppointmentCardState extends State<AppointmentCard> {
Future<void> handleAppointmentNextAction(nextAction, BuildContext context) async {
switch (nextAction) {
case 0:
case 110:
// No action needed
_goToDetails(context);
break;

Loading…
Cancel
Save