commit
5a1bd6a5b8
@ -0,0 +1 @@
|
|||||||
|
{"nm":"Comp 1","ddd":0,"h":100,"w":100,"meta":{"g":"@lottiefiles/toolkit-js 0.33.2"},"layers":[{"ty":4,"nm":"Shape Layer 2","sr":1,"st":0,"op":300,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[5.277,-32.723,0],"ix":1},"s":{"a":0,"k":[4.91,4.91,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[50.2,50.18,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 2","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[102.555,102.555],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0941,0.7608,0.451],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[3.277,-34.527],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":2,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[102.555,102.555],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0941,0.7608,0.451],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100],"t":0},{"s":[295,295],"t":60}],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[3.277,-34.527],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":0},{"s":[0],"t":60}],"ix":7}}]}],"ind":1}],"v":"5.5.7","fr":60,"op":61,"ip":0,"assets":[]}
|
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12 2.75H11.9278C9.92082 2.74998 8.31557 2.74996 7.0558 2.91933C5.75291 3.0945 4.67453 3.46676 3.82064 4.32064C2.96676 5.17453 2.5945 6.25291 2.41933 7.5558C2.24996 8.81557 2.24998 10.4208 2.25 12.4278V12.5722C2.24998 14.5792 2.24996 16.1844 2.41933 17.4442C2.5945 18.7471 2.96676 19.8255 3.82064 20.6794C4.67453 21.5332 5.75291 21.9055 7.0558 22.0807C8.31558 22.25 9.92083 22.25 11.9278 22.25H12.0722C14.0792 22.25 15.6844 22.25 16.9442 22.0807C18.2471 21.9055 19.3255 21.5332 20.1794 20.6794C21.0332 19.8255 21.4055 18.7471 21.5807 17.4442C21.75 16.1844 21.75 14.5792 21.75 12.5722V12.5C21.75 11.9615 21.3135 11.525 20.775 11.525C20.2365 11.525 19.8 11.9615 19.8 12.5C19.8 14.5959 19.7979 16.0697 19.6481 17.1844C19.502 18.271 19.2317 18.8693 18.8005 19.3005C18.3693 19.7317 17.771 20.002 16.6844 20.1481C15.5697 20.2979 14.0959 20.3 12 20.3C9.90415 20.3 8.43035 20.2979 7.31564 20.1481C6.22898 20.002 5.63068 19.7317 5.1995 19.3005C4.76831 18.8693 4.49804 18.271 4.35194 17.1844C4.20207 16.0697 4.2 14.5959 4.2 12.5C4.2 10.4042 4.20207 8.93035 4.35194 7.81564C4.49804 6.72898 4.76831 6.13068 5.1995 5.6995C5.63068 5.26831 6.22898 4.99804 7.31564 4.85194C8.43035 4.70207 9.90415 4.7 12 4.7C12.5385 4.7 12.975 4.26348 12.975 3.725C12.975 3.18652 12.5385 2.75 12 2.75Z" fill="#2E3039"/>
|
||||||
|
<path d="M17.0855 3.5503C18.1526 2.48323 19.8827 2.48323 20.9497 3.5503C22.0168 4.61736 22.0168 6.34742 20.9497 7.41448L20.078 8.28615L16.2139 4.42188L17.0855 3.5503Z" fill="#2E3039"/>
|
||||||
|
<path d="M15.1533 5.48254L19.0174 9.34682L14.2337 14.1306C13.2653 15.0992 12.6734 15.6912 11.9448 16.0983C11.5383 16.3255 10.9218 16.5239 10.291 16.6994C9.64198 16.88 8.89524 17.0578 8.18242 17.2275L8.17373 17.2296C7.92037 17.2899 7.65385 17.2145 7.46969 17.0303C7.28552 16.8462 7.21009 16.5796 7.27041 16.3263L7.27249 16.3175C7.44221 15.6047 7.62 14.858 7.8006 14.209C7.97615 13.5782 8.17455 12.9617 8.40167 12.5553C8.80884 11.8266 9.40083 11.2348 10.3694 10.2664L15.1533 5.48254Z" fill="#2E3039"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
@ -1,3 +1,3 @@
|
|||||||
<svg width="18" height="12" viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M17.7495 6.00047C17.7495 5.62691 17.5839 5.28034 17.427 5.02011C17.2577 4.7393 17.0301 4.44937 16.7803 4.16669C16.2794 3.59962 15.6257 2.99064 14.9913 2.43977C14.3532 1.88567 13.7173 1.37546 13.2423 1.00468C13.0044 0.818986 12.8059 0.66755 12.6665 0.562239C12.5968 0.509569 12.5418 0.468397 12.5039 0.440203L12.4604 0.407818L12.4488 0.399264L12.4448 0.396304C12.1113 0.150642 11.6414 0.221533 11.3957 0.555035C11.1501 0.888521 11.2213 1.358 11.5547 1.60367L11.5674 1.61308L11.6075 1.64285C11.6429 1.66925 11.6953 1.7085 11.7623 1.75911C11.8964 1.86036 12.0885 2.00695 12.3193 2.18713C12.7818 2.5481 13.3959 3.04099 14.0078 3.57235C14.6234 4.10694 15.2197 4.66576 15.6562 5.15983C15.6838 5.19108 15.7105 5.2218 15.7364 5.25195L0.999512 5.25196C0.585298 5.25196 0.249512 5.58774 0.249512 6.00195C0.249512 6.41617 0.585299 6.75196 0.999512 6.75196L15.7338 6.75195C15.7088 6.78116 15.6829 6.81088 15.6562 6.84111C15.2197 7.33518 14.6234 7.89401 14.0078 8.4286C13.3959 8.95995 12.7818 9.45285 12.3193 9.81382C12.0885 9.99399 11.8964 10.1406 11.7623 10.2418C11.6953 10.2925 11.6429 10.3317 11.6075 10.3581L11.5674 10.3879L11.5547 10.3973C11.2213 10.6429 11.1501 11.1124 11.3957 11.4459C11.6414 11.7794 12.1113 11.8503 12.4448 11.6046L12.4488 11.6017L12.4604 11.5931L12.5039 11.5607C12.5418 11.5326 12.5968 11.4914 12.6665 11.4387C12.8059 11.3334 13.0044 11.182 13.2423 10.9963C13.7173 10.6255 14.3532 10.1153 14.9913 9.56118C15.6257 9.01031 16.2794 8.40133 16.7803 7.83425C17.0301 7.55158 17.2577 7.26165 17.427 6.98083C17.5829 6.72217 17.7475 6.37819 17.7495 6.0072" fill="white"/>
|
<path d="M28.7495 19.9995C28.7495 19.6259 28.5839 19.2794 28.427 19.0191C28.2577 18.7383 28.0301 18.4484 27.7803 18.1657C27.2794 17.5986 26.6257 16.9897 25.9913 16.4388C25.3532 15.8847 24.7173 15.3745 24.2423 15.0037C24.0044 14.818 23.8059 14.6666 23.6665 14.5613C23.5968 14.5086 23.5418 14.4674 23.5039 14.4392L23.4604 14.4068L23.4488 14.3983L23.4448 14.3953C23.1113 14.1497 22.6414 14.2206 22.3957 14.5541C22.1501 14.8875 22.2213 15.357 22.5547 15.6027L22.5674 15.6121L22.6075 15.6419C22.6429 15.6683 22.6953 15.7075 22.7623 15.7581C22.8964 15.8594 23.0885 16.006 23.3193 16.1862C23.7818 16.5471 24.3959 17.04 25.0078 17.5714C25.6234 18.106 26.2197 18.6648 26.6562 19.1589C26.6838 19.1901 26.7105 19.2208 26.7364 19.251L11.9995 19.251C11.5853 19.251 11.2495 19.5868 11.2495 20.001C11.2495 20.4152 11.5853 20.751 11.9995 20.751L26.7338 20.751C26.7088 20.7802 26.6829 20.8099 26.6562 20.8401C26.2197 21.3342 25.6234 21.893 25.0078 22.4276C24.3959 22.959 23.7818 23.4519 23.3193 23.8128C23.0885 23.993 22.8964 24.1396 22.7623 24.2409C22.6953 24.2915 22.6429 24.3307 22.6075 24.3571L22.5674 24.3869L22.5547 24.3963C22.2213 24.642 22.1501 25.1115 22.3957 25.4449C22.6414 25.7784 23.1113 25.8493 23.4448 25.6037L23.4488 25.6007L23.4604 25.5922L23.5039 25.5598C23.5418 25.5316 23.5968 25.4904 23.6665 25.4377C23.8059 25.3324 24.0044 25.181 24.2423 24.9953C24.7173 24.6245 25.3532 24.1143 25.9913 23.5602C26.6257 23.0093 27.2794 22.4003 27.7803 21.8333C28.0301 21.5506 28.2577 21.2607 28.427 20.9799C28.5829 20.7212 28.7475 20.3772 28.7495 20.0062" fill="#2E3039"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="20" height="14" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12.43 13.823C12.24 13.823 12.05 13.753 11.9 13.603C11.61 13.313 11.61 12.833 11.9 12.543L17.44 7.00305L11.9 1.46305C11.61 1.17305 11.61 0.693047 11.9 0.403047C12.19 0.113047 12.67 0.113047 12.96 0.403047L19.03 6.47305C19.32 6.76305 19.32 7.24305 19.03 7.53305L12.96 13.603C12.81 13.753 12.62 13.823 12.43 13.823Z" fill="#2E3039"/>
|
||||||
|
<path d="M18.33 7.75305H1.5C1.09 7.75305 0.75 7.41305 0.75 7.00305C0.75 6.59305 1.09 6.25305 1.5 6.25305H18.33C18.74 6.25305 19.08 6.59305 19.08 7.00305C19.08 7.41305 18.74 7.75305 18.33 7.75305Z" fill="#2E3039"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 666 B |
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="9.5" cy="9.5" r="6.5" fill="#18C273"/>
|
||||||
|
<circle cx="9.5" cy="9.5" r="8" stroke="#18C273" stroke-opacity="0.31" stroke-width="3"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 252 B |
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 1.75C3.58579 1.75 3.25 2.08579 3.25 2.5C3.25 2.91421 3.58579 3.25 4 3.25H4.25L4.25 5.5C4.25 8.58811 6.05618 11.2544 8.66976 12.5C6.05618 13.7456 4.25 16.4119 4.25 19.5L4.25 21.75H4C3.58579 21.75 3.25 22.0858 3.25 22.5C3.25 22.9142 3.58579 23.25 4 23.25L20 23.25C20.4142 23.25 20.75 22.9142 20.75 22.5C20.75 22.0858 20.4142 21.75 20 21.75H19.75V19.5C19.75 16.4119 17.9438 13.7456 15.3302 12.5C17.9438 11.2544 19.75 8.58811 19.75 5.5V3.25H20C20.4142 3.25 20.75 2.91421 20.75 2.5C20.75 2.08579 20.4142 1.75 20 1.75L4 1.75ZM18.25 3.25L5.75 3.25L5.75 5.5C5.75 8.95178 8.54822 11.75 12 11.75C15.4518 11.75 18.25 8.95178 18.25 5.5V3.25ZM18.25 21.75L18.25 19.5C18.25 16.0482 15.4518 13.25 12 13.25C8.54822 13.25 5.75 16.0482 5.75 19.5L5.75 21.75L18.25 21.75Z" fill="#2B353E"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 927 B |
@ -0,0 +1,206 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/api/api_client.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/api_consts.dart';
|
||||||
|
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/immediate_livecare/models/resp_models/get_livecare_immediate_clinics_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_fees_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_patient_livecare_history_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/services/logger_service.dart';
|
||||||
|
|
||||||
|
abstract class ImmediateLiveCareRepo {
|
||||||
|
Future<Either<Failure, GenericApiModel<List<GetLiveCareClinicListResponseModel>>>> getLiveCareImmediateClinicsList(int age, int genderID, {Function(dynamic)? onSuccess, Function(String)? onError});
|
||||||
|
|
||||||
|
Future<Either<Failure, GenericApiModel<LiveCareImmediateAppointmentFeesList>>> getLiveCareImmediateAppointmentFees(int age, int genderID, int serviceID,
|
||||||
|
{Function(dynamic)? onSuccess, Function(String)? onError});
|
||||||
|
|
||||||
|
Future<Either<Failure, GenericApiModel<dynamic>>> addNewCallRequestForImmediateLiveCare(
|
||||||
|
int age, int gender, int serviceID, String clientRequestID, int callTypeID, bool isPharma, String deviceToken, String voipToken,
|
||||||
|
{Function(dynamic)? onSuccess, Function(String)? onError});
|
||||||
|
|
||||||
|
Future<Either<Failure, GenericApiModel<List<PatientLiveCareHistory>>>> getPatientLiveCareHistory({Function(dynamic)? onSuccess, Function(String)? onError});
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImmediateLiveCareRepoImp implements ImmediateLiveCareRepo {
|
||||||
|
final ApiClient apiClient;
|
||||||
|
final LoggerService loggerService;
|
||||||
|
|
||||||
|
ImmediateLiveCareRepoImp({required this.loggerService, required this.apiClient});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Either<Failure, GenericApiModel<List<GetLiveCareClinicListResponseModel>>>> getLiveCareImmediateClinicsList(int age, int genderID,
|
||||||
|
{Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||||
|
Map<String, dynamic> mapDevice = {
|
||||||
|
"Age": age,
|
||||||
|
"Gender": genderID,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
GenericApiModel<List<GetLiveCareClinicListResponseModel>>? apiResponse;
|
||||||
|
Failure? failure;
|
||||||
|
await apiClient.post(
|
||||||
|
GET_LIVECARE_CLINICS,
|
||||||
|
body: mapDevice,
|
||||||
|
onFailure: (error, statusCode, {messageStatus, failureType}) {
|
||||||
|
failure = failureType;
|
||||||
|
onError!(error);
|
||||||
|
},
|
||||||
|
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
|
||||||
|
try {
|
||||||
|
final list = response['PatientER_GetClinicsList'];
|
||||||
|
|
||||||
|
final clinicsList = list.map((item) => GetLiveCareClinicListResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetLiveCareClinicListResponseModel>();
|
||||||
|
|
||||||
|
apiResponse = GenericApiModel<List<GetLiveCareClinicListResponseModel>>(
|
||||||
|
messageStatus: messageStatus,
|
||||||
|
statusCode: statusCode,
|
||||||
|
errorMessage: null,
|
||||||
|
data: clinicsList,
|
||||||
|
);
|
||||||
|
} 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<LiveCareImmediateAppointmentFeesList>>> getLiveCareImmediateAppointmentFees(int age, int genderID, int serviceID,
|
||||||
|
{Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||||
|
Map<String, dynamic> mapDevice = {
|
||||||
|
"Age": age,
|
||||||
|
"Gender": genderID,
|
||||||
|
"ServiceID": serviceID,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
GenericApiModel<LiveCareImmediateAppointmentFeesList>? apiResponse;
|
||||||
|
Failure? failure;
|
||||||
|
await apiClient.post(
|
||||||
|
GET_ER_APPOINTMENT_FEES,
|
||||||
|
body: mapDevice,
|
||||||
|
onFailure: (error, statusCode, {messageStatus, failureType}) {
|
||||||
|
failure = failureType;
|
||||||
|
onError!(error);
|
||||||
|
},
|
||||||
|
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
|
||||||
|
try {
|
||||||
|
final respObject = response['GetERAppointmentFeesList'];
|
||||||
|
|
||||||
|
final liveCareFeesObj = LiveCareImmediateAppointmentFeesList.fromJson(respObject);
|
||||||
|
|
||||||
|
apiResponse = GenericApiModel<LiveCareImmediateAppointmentFeesList>(
|
||||||
|
messageStatus: messageStatus,
|
||||||
|
statusCode: statusCode,
|
||||||
|
errorMessage: null,
|
||||||
|
data: liveCareFeesObj,
|
||||||
|
);
|
||||||
|
} 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>> addNewCallRequestForImmediateLiveCare(
|
||||||
|
int age, int gender, int serviceID, String clientRequestID, int callTypeID, bool isPharma, String deviceToken, String voipToken,
|
||||||
|
{Function(dynamic p1)? onSuccess, Function(String p1)? onError}) async {
|
||||||
|
Map<String, dynamic> mapDevice = {
|
||||||
|
"IsPharmacy": isPharma,
|
||||||
|
"ErServiceID": serviceID,
|
||||||
|
"ClientRequestID": clientRequestID,
|
||||||
|
"DeviceToken": deviceToken,
|
||||||
|
"VoipToken": voipToken,
|
||||||
|
"IsFlutter": true,
|
||||||
|
"DeviceType": Platform.isIOS ? 'iOS' : 'Android',
|
||||||
|
"Age": age,
|
||||||
|
"Gender": gender,
|
||||||
|
"IsVoip": Platform.isIOS ? true : false,
|
||||||
|
"CallTypeID": callTypeID
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
GenericApiModel<dynamic>? apiResponse;
|
||||||
|
Failure? failure;
|
||||||
|
await apiClient.post(
|
||||||
|
ADD_NEW_CALL_FOR_PATIENT_ER,
|
||||||
|
body: mapDevice,
|
||||||
|
onFailure: (error, statusCode, {messageStatus, failureType}) {
|
||||||
|
failure = failureType;
|
||||||
|
onError!(error);
|
||||||
|
},
|
||||||
|
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
|
||||||
|
try {
|
||||||
|
apiResponse = GenericApiModel<dynamic>(
|
||||||
|
messageStatus: messageStatus,
|
||||||
|
statusCode: statusCode,
|
||||||
|
errorMessage: null,
|
||||||
|
data: true,
|
||||||
|
);
|
||||||
|
} 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<PatientLiveCareHistory>>>> getPatientLiveCareHistory({Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||||
|
Map<String, dynamic> mapDevice = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
GenericApiModel<List<PatientLiveCareHistory>>? apiResponse;
|
||||||
|
Failure? failure;
|
||||||
|
await apiClient.post(
|
||||||
|
GET_LIVECARE_HISTORY,
|
||||||
|
body: mapDevice,
|
||||||
|
onFailure: (error, statusCode, {messageStatus, failureType}) {
|
||||||
|
failure = failureType;
|
||||||
|
onError!(error);
|
||||||
|
},
|
||||||
|
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
|
||||||
|
try {
|
||||||
|
final list = response['ErRequestHistoryList'];
|
||||||
|
|
||||||
|
final liveCareHistoryList = list.map((item) => PatientLiveCareHistory.fromJson(item as Map<String, dynamic>)).toList().cast<PatientLiveCareHistory>();
|
||||||
|
|
||||||
|
apiResponse = GenericApiModel<List<PatientLiveCareHistory>>(
|
||||||
|
messageStatus: messageStatus,
|
||||||
|
statusCode: statusCode,
|
||||||
|
errorMessage: null,
|
||||||
|
data: liveCareHistoryList,
|
||||||
|
);
|
||||||
|
} 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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
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/dependencies.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_repo.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_clinics_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_fees_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_patient_livecare_history_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
|
||||||
|
|
||||||
|
import '../../services/navigation_service.dart';
|
||||||
|
|
||||||
|
class ImmediateLiveCareViewModel extends ChangeNotifier {
|
||||||
|
ImmediateLiveCareViewModel({
|
||||||
|
required this.immediateLiveCareRepo,
|
||||||
|
required this.errorHandlerService,
|
||||||
|
required this.navigationService,
|
||||||
|
required this.myAppointmentsViewModel,
|
||||||
|
});
|
||||||
|
|
||||||
|
ImmediateLiveCareRepo immediateLiveCareRepo;
|
||||||
|
ErrorHandlerService errorHandlerService;
|
||||||
|
final NavigationService navigationService;
|
||||||
|
MyAppointmentsViewModel myAppointmentsViewModel;
|
||||||
|
|
||||||
|
List<GetLiveCareClinicListResponseModel> immediateLiveCareClinicsList = [];
|
||||||
|
bool isImmediateLiveCareClinicsLoading = false;
|
||||||
|
int liveCareSelectedCallType = 0; // 1- Video, 2- Audio, 3- Phone
|
||||||
|
late GetLiveCareClinicListResponseModel immediateLiveCareSelectedClinic;
|
||||||
|
late LiveCareImmediateAppointmentFeesList liveCareImmediateAppointmentFeesList;
|
||||||
|
|
||||||
|
List<PatientLiveCareHistory> patientLiveCareHistoryList = [];
|
||||||
|
bool patientHasPendingLiveCareRequest = false;
|
||||||
|
|
||||||
|
late AppState _appState;
|
||||||
|
|
||||||
|
initImmediateLiveCare() {
|
||||||
|
_appState = getIt<AppState>();
|
||||||
|
immediateLiveCareClinicsList = [];
|
||||||
|
patientLiveCareHistoryList = [];
|
||||||
|
isImmediateLiveCareClinicsLoading = true;
|
||||||
|
patientHasPendingLiveCareRequest = false;
|
||||||
|
liveCareSelectedCallType = 0; // 1- Video, 2- Audio, 3- Phone
|
||||||
|
immediateLiveCareSelectedClinic = GetLiveCareClinicListResponseModel();
|
||||||
|
liveCareImmediateAppointmentFeesList = LiveCareImmediateAppointmentFeesList();
|
||||||
|
}
|
||||||
|
|
||||||
|
setLiveCareSelectedCallType(int value) {
|
||||||
|
liveCareSelectedCallType = value;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
setImmediateLiveCareSelectedClinic(GetLiveCareClinicListResponseModel clinic) {
|
||||||
|
immediateLiveCareSelectedClinic = clinic;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getLiveCareImmediateClinicsList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||||
|
immediateLiveCareClinicsList.clear();
|
||||||
|
isImmediateLiveCareClinicsLoading = true;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
final result = await immediateLiveCareRepo.getLiveCareImmediateClinicsList(_appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!);
|
||||||
|
|
||||||
|
result.fold(
|
||||||
|
(failure) async => await errorHandlerService.handleError(failure: failure),
|
||||||
|
(apiResponse) {
|
||||||
|
if (apiResponse.messageStatus == 2) {
|
||||||
|
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
|
||||||
|
} else if (apiResponse.messageStatus == 1) {
|
||||||
|
immediateLiveCareClinicsList = apiResponse.data!;
|
||||||
|
|
||||||
|
immediateLiveCareClinicsList.sort((a, b) => b.isOnline!.compareTo(a.isOnline!));
|
||||||
|
|
||||||
|
isImmediateLiveCareClinicsLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
if (onSuccess != null) {
|
||||||
|
onSuccess(apiResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getLiveCareImmediateAppointmentFees({Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||||
|
final result =
|
||||||
|
await immediateLiveCareRepo.getLiveCareImmediateAppointmentFees(_appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!, immediateLiveCareSelectedClinic.serviceID!);
|
||||||
|
|
||||||
|
result.fold(
|
||||||
|
(failure) async {
|
||||||
|
onError!(failure.message);
|
||||||
|
},
|
||||||
|
(apiResponse) {
|
||||||
|
if (apiResponse.messageStatus == 2) {
|
||||||
|
onError!(apiResponse.errorMessage ?? "Unknown error occurred");
|
||||||
|
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
|
||||||
|
} else if (apiResponse.messageStatus == 1) {
|
||||||
|
liveCareImmediateAppointmentFeesList = apiResponse.data!;
|
||||||
|
notifyListeners();
|
||||||
|
if (onSuccess != null) {
|
||||||
|
onSuccess(apiResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addNewCallRequestForImmediateLiveCare(String transID, {Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||||
|
final result = await immediateLiveCareRepo.addNewCallRequestForImmediateLiveCare(_appState.getAuthenticatedUser()!.age!, _appState.getAuthenticatedUser()!.gender!,
|
||||||
|
immediateLiveCareSelectedClinic.serviceID!, transID, liveCareSelectedCallType, false, _appState.deviceToken, await Utils.getStringFromPrefs(CacheConst.voipToken));
|
||||||
|
|
||||||
|
result.fold(
|
||||||
|
(failure) async {
|
||||||
|
onError!(failure.message);
|
||||||
|
},
|
||||||
|
(apiResponse) {
|
||||||
|
if (apiResponse.messageStatus == 2) {
|
||||||
|
onError!(apiResponse.errorMessage ?? "Unknown error occurred");
|
||||||
|
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
|
||||||
|
} else if (apiResponse.messageStatus == 1) {
|
||||||
|
notifyListeners();
|
||||||
|
if (onSuccess != null) {
|
||||||
|
onSuccess(apiResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getPatientLiveCareHistory({Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||||
|
final result = await immediateLiveCareRepo.getPatientLiveCareHistory();
|
||||||
|
|
||||||
|
result.fold(
|
||||||
|
(failure) async {
|
||||||
|
onError!(failure.message);
|
||||||
|
},
|
||||||
|
(apiResponse) {
|
||||||
|
if (apiResponse.messageStatus == 2) {
|
||||||
|
onError!(apiResponse.errorMessage ?? "Unknown error occurred");
|
||||||
|
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
|
||||||
|
} else if (apiResponse.messageStatus == 1) {
|
||||||
|
patientLiveCareHistoryList = apiResponse.data!;
|
||||||
|
if (patientLiveCareHistoryList.isNotEmpty) {
|
||||||
|
if (patientLiveCareHistoryList[0].callStatus! < 4) {
|
||||||
|
patientHasPendingLiveCareRequest = true;
|
||||||
|
} else {
|
||||||
|
patientHasPendingLiveCareRequest = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
patientHasPendingLiveCareRequest = false;
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
if (onSuccess != null) {
|
||||||
|
onSuccess(apiResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
class GetLiveCareClinicListResponseModel {
|
||||||
|
int? iD;
|
||||||
|
int? serviceID;
|
||||||
|
String? serviceName;
|
||||||
|
String? serviceNameN;
|
||||||
|
int? clinicID;
|
||||||
|
int? age;
|
||||||
|
bool? isCheckAgeBelow;
|
||||||
|
int? gender;
|
||||||
|
bool? isActive;
|
||||||
|
String? createdOn;
|
||||||
|
String? createdBy;
|
||||||
|
int? isOnline;
|
||||||
|
bool? projectOutSA;
|
||||||
|
List<ShiftTimings>? shiftTimings;
|
||||||
|
|
||||||
|
GetLiveCareClinicListResponseModel(
|
||||||
|
{this.iD,
|
||||||
|
this.serviceID,
|
||||||
|
this.serviceName,
|
||||||
|
this.serviceNameN,
|
||||||
|
this.clinicID,
|
||||||
|
this.age,
|
||||||
|
this.isCheckAgeBelow,
|
||||||
|
this.gender,
|
||||||
|
this.isActive,
|
||||||
|
this.createdOn,
|
||||||
|
this.createdBy,
|
||||||
|
this.isOnline,
|
||||||
|
this.projectOutSA,
|
||||||
|
this.shiftTimings});
|
||||||
|
|
||||||
|
GetLiveCareClinicListResponseModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
iD = json['ID'];
|
||||||
|
serviceID = json['ServiceID'];
|
||||||
|
serviceName = json['ServiceName'];
|
||||||
|
serviceNameN = json['ServiceNameN'];
|
||||||
|
clinicID = json['ClinicID'];
|
||||||
|
age = json['Age'];
|
||||||
|
isCheckAgeBelow = json['IsCheckAgeBelow'];
|
||||||
|
gender = json['Gender'];
|
||||||
|
isActive = json['IsActive'];
|
||||||
|
createdOn = json['CreatedOn'];
|
||||||
|
createdBy = json['CreatedBy'];
|
||||||
|
isOnline = json['IsOnline'];
|
||||||
|
projectOutSA = json['ProjectOutSA'];
|
||||||
|
if (json['ShiftTimings'] != null) {
|
||||||
|
shiftTimings = <ShiftTimings>[];
|
||||||
|
json['ShiftTimings'].forEach((v) {
|
||||||
|
shiftTimings!.add(new ShiftTimings.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = Map<String, dynamic>();
|
||||||
|
data['ID'] = this.iD;
|
||||||
|
data['ServiceID'] = this.serviceID;
|
||||||
|
data['ServiceName'] = this.serviceName;
|
||||||
|
data['ServiceNameN'] = this.serviceNameN;
|
||||||
|
data['ClinicID'] = this.clinicID;
|
||||||
|
data['Age'] = this.age;
|
||||||
|
data['IsCheckAgeBelow'] = this.isCheckAgeBelow;
|
||||||
|
data['Gender'] = this.gender;
|
||||||
|
data['IsActive'] = this.isActive;
|
||||||
|
data['CreatedOn'] = this.createdOn;
|
||||||
|
data['CreatedBy'] = this.createdBy;
|
||||||
|
data['IsOnline'] = this.isOnline;
|
||||||
|
data['ProjectOutSA'] = this.projectOutSA;
|
||||||
|
if (this.shiftTimings != null) {
|
||||||
|
data['ShiftTimings'] = this.shiftTimings!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShiftTimings {
|
||||||
|
String? endTime;
|
||||||
|
int? shiftID;
|
||||||
|
String? startTime;
|
||||||
|
|
||||||
|
ShiftTimings({this.endTime, this.shiftID, this.startTime});
|
||||||
|
|
||||||
|
ShiftTimings.fromJson(Map<String, dynamic> json) {
|
||||||
|
endTime = json['EndTime'];
|
||||||
|
shiftID = json['ShiftID'];
|
||||||
|
startTime = json['StartTime'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = Map<String, dynamic>();
|
||||||
|
data['EndTime'] = this.endTime;
|
||||||
|
data['ShiftID'] = this.shiftID;
|
||||||
|
data['StartTime'] = this.startTime;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
class LiveCareImmediateAppointmentFeesList {
|
||||||
|
String? amount;
|
||||||
|
String? companyName;
|
||||||
|
bool? isInsured;
|
||||||
|
bool? isShowInsuranceUpdateModule;
|
||||||
|
bool? isCash;
|
||||||
|
bool? isEligible;
|
||||||
|
String? tax;
|
||||||
|
String? total;
|
||||||
|
String? currency;
|
||||||
|
|
||||||
|
LiveCareImmediateAppointmentFeesList({this.amount, this.companyName, this.isInsured, this.isShowInsuranceUpdateModule, this.tax, this.total, this.currency});
|
||||||
|
|
||||||
|
LiveCareImmediateAppointmentFeesList.fromJson(Map<String, dynamic> json) {
|
||||||
|
amount = json['Amount'];
|
||||||
|
companyName = json['CompanyName'];
|
||||||
|
isInsured = json['IsInsured'];
|
||||||
|
isCash = json['IsCash'];
|
||||||
|
isEligible = json['IsEligible'];
|
||||||
|
isShowInsuranceUpdateModule = json['IsShowInsuranceUpdateModule'];
|
||||||
|
tax = json['Tax'];
|
||||||
|
total = json['Total'];
|
||||||
|
currency = json['currency'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['Amount'] = this.amount;
|
||||||
|
data['CompanyName'] = this.companyName;
|
||||||
|
data['IsInsured'] = this.isInsured;
|
||||||
|
data['IsShowInsuranceUpdateModule'] = this.isShowInsuranceUpdateModule;
|
||||||
|
data['Tax'] = this.tax;
|
||||||
|
data['Total'] = this.total;
|
||||||
|
data['currency'] = this.currency;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
class PatientLiveCareHistory {
|
||||||
|
String? appointmentNo;
|
||||||
|
String? arrivalTime;
|
||||||
|
num? callDuration;
|
||||||
|
int? callStatus;
|
||||||
|
String? clientRequestID;
|
||||||
|
String? doctorID;
|
||||||
|
String? doctorName;
|
||||||
|
String? doctorNameN;
|
||||||
|
String? doctorTitle;
|
||||||
|
String? exWaitingTime;
|
||||||
|
bool? isAppointmentHaveRating;
|
||||||
|
int? patCount;
|
||||||
|
int? projectID;
|
||||||
|
String? sArrivalTime;
|
||||||
|
int? serviceID;
|
||||||
|
String? stringCallStatus;
|
||||||
|
int? vCID;
|
||||||
|
int? watingtimeInteger;
|
||||||
|
|
||||||
|
PatientLiveCareHistory(
|
||||||
|
{this.appointmentNo,
|
||||||
|
this.arrivalTime,
|
||||||
|
this.callDuration,
|
||||||
|
this.callStatus,
|
||||||
|
this.clientRequestID,
|
||||||
|
this.doctorID,
|
||||||
|
this.doctorName,
|
||||||
|
this.doctorNameN,
|
||||||
|
this.doctorTitle,
|
||||||
|
this.exWaitingTime,
|
||||||
|
this.isAppointmentHaveRating,
|
||||||
|
this.patCount,
|
||||||
|
this.projectID,
|
||||||
|
this.sArrivalTime,
|
||||||
|
this.serviceID,
|
||||||
|
this.stringCallStatus,
|
||||||
|
this.vCID,
|
||||||
|
this.watingtimeInteger});
|
||||||
|
|
||||||
|
PatientLiveCareHistory.fromJson(Map<String, dynamic> json) {
|
||||||
|
appointmentNo = json['AppointmentNo'];
|
||||||
|
arrivalTime = json['ArrivalTime'];
|
||||||
|
callDuration = json['CallDuration'];
|
||||||
|
callStatus = json['CallStatus'];
|
||||||
|
clientRequestID = json['ClientRequestID'];
|
||||||
|
doctorID = json['DoctorID'];
|
||||||
|
doctorName = json['DoctorName'];
|
||||||
|
doctorNameN = json['DoctorNameN'];
|
||||||
|
doctorTitle = json['DoctorTitle'];
|
||||||
|
exWaitingTime = json['Ex_WaitingTime'];
|
||||||
|
isAppointmentHaveRating = json['IsAppointmentHaveRating'];
|
||||||
|
patCount = json['Pat_Count'];
|
||||||
|
projectID = json['ProjectID'];
|
||||||
|
sArrivalTime = json['SArrivalTime'];
|
||||||
|
serviceID = json['ServiceID'];
|
||||||
|
stringCallStatus = json['StringCallStatus'];
|
||||||
|
vCID = json['VC_ID'];
|
||||||
|
watingtimeInteger = json['WatingtimeInteger'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['AppointmentNo'] = this.appointmentNo;
|
||||||
|
data['ArrivalTime'] = this.arrivalTime;
|
||||||
|
data['CallDuration'] = this.callDuration;
|
||||||
|
data['CallStatus'] = this.callStatus;
|
||||||
|
data['ClientRequestID'] = this.clientRequestID;
|
||||||
|
data['DoctorID'] = this.doctorID;
|
||||||
|
data['DoctorName'] = this.doctorName;
|
||||||
|
data['DoctorNameN'] = this.doctorNameN;
|
||||||
|
data['DoctorTitle'] = this.doctorTitle;
|
||||||
|
data['Ex_WaitingTime'] = this.exWaitingTime;
|
||||||
|
data['IsAppointmentHaveRating'] = this.isAppointmentHaveRating;
|
||||||
|
data['Pat_Count'] = this.patCount;
|
||||||
|
data['ProjectID'] = this.projectID;
|
||||||
|
data['SArrivalTime'] = this.sArrivalTime;
|
||||||
|
data['ServiceID'] = this.serviceID;
|
||||||
|
data['StringCallStatus'] = this.stringCallStatus;
|
||||||
|
data['VC_ID'] = this.vCID;
|
||||||
|
data['WatingtimeInteger'] = this.watingtimeInteger;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,304 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
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/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/book_appointments/book_appointments_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/widgets/select_livecare_call_type.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.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/buttons/custom_button.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smooth_corner/smooth_corner.dart';
|
||||||
|
|
||||||
|
class ImmediateLiveCarePaymentDetails extends StatelessWidget {
|
||||||
|
ImmediateLiveCarePaymentDetails({super.key});
|
||||||
|
|
||||||
|
late ImmediateLiveCareViewModel immediateLiveCareViewModel;
|
||||||
|
late AppState appState;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false);
|
||||||
|
appState = getIt.get<AppState>();
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.scaffoldBgColor,
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CollapsingListView(
|
||||||
|
title: "Review LiveCare Request".needTranslation,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24.h),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
LocaleKeys.patientInfo.tr(context: context).toText16(isBold: true),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.h),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg,
|
||||||
|
width: 52.h,
|
||||||
|
height: 52.h,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.h),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText16(isBold: true),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} Years Old"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
"Clinic Information".needTranslation.toText16(isBold: true),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.h),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Utils.buildSvgWithAssets(icon: AppAssets.generic_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain),
|
||||||
|
SizedBox(width: 8.h),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
(appState.isArabic()
|
||||||
|
? immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceNameN
|
||||||
|
: immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceName)!
|
||||||
|
.toText16(isBold: true),
|
||||||
|
// SizedBox(height: 8.h),
|
||||||
|
// AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} Years Old"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
"Selected LiveCare Type".needTranslation.toText16(isBold: true),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Consumer<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
|
||||||
|
return Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.h),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 32.h, height: 32.h, fit: BoxFit.contain),
|
||||||
|
SizedBox(width: 8.h),
|
||||||
|
getLiveCareType(immediateLiveCareViewModel.liveCareSelectedCallType).toText16(isBold: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Utils.buildSvgWithAssets(icon: AppAssets.edit_icon, width: 24.h, height: 24.h, fit: BoxFit.contain),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).onPress(() {
|
||||||
|
showCommonBottomSheetWithoutHeight(context, child: SelectLiveCareCallType(immediateLiveCareViewModel: immediateLiveCareViewModel), callBackFunc: () async {
|
||||||
|
debugPrint("Selected Call Type: ${immediateLiveCareViewModel.liveCareSelectedCallType}");
|
||||||
|
}, title: "Select LiveCare call type".needTranslation, isCloseButtonVisible: true, isFullScreen: false);
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
SizedBox(height: 24.h)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.isCash ?? true)
|
||||||
|
? Container(
|
||||||
|
height: 50.h,
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: AppColors.secondaryLightRedBorderColor,
|
||||||
|
shape: SmoothRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
|
||||||
|
smoothness: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
"Insurance expired or inactive".needTranslation.toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h),
|
||||||
|
CustomButton(
|
||||||
|
text: LocaleKeys.updateInsurance.tr(context: context),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
CustomPageRoute(
|
||||||
|
page: InsuranceHomePage(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
backgroundColor: AppColors.primaryRedColor,
|
||||||
|
borderColor: AppColors.secondaryLightRedBorderColor,
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
borderRadius: 8,
|
||||||
|
padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
|
||||||
|
height: 30.h,
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
|
||||||
|
SizedBox(height: 17.h),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
"Amount before tax".needTranslation.toText14(isBold: true),
|
||||||
|
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.amount!.toText16(isBold: true), AppColors.blackColor, 13,
|
||||||
|
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor),
|
||||||
|
Utils.getPaymentAmountWithSymbol(
|
||||||
|
immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.tax!.toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
|
||||||
|
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
SizedBox(height: 17.h),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
SizedBox(width: 150.h, child: Utils.getPaymentMethods()),
|
||||||
|
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!.toText24(isBold: true), AppColors.blackColor, 17,
|
||||||
|
isSaudiCurrency: immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
CustomButton(
|
||||||
|
text: LocaleKeys.payNow.tr(context: context),
|
||||||
|
onPressed: () async {
|
||||||
|
await askVideoCallPermission().then((val) {
|
||||||
|
if (val) {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
CustomPageRoute(
|
||||||
|
page: ImmediateLiveCarePaymentPage(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
title: LocaleKeys.notice.tr(context: context),
|
||||||
|
context,
|
||||||
|
child: Utils.getWarningWidget(
|
||||||
|
loadingText:
|
||||||
|
"LiveCare requires Camera, Microphone & Location permissions to enable virtual consultation between patient & doctor, Please allow these to proceed.".needTranslation,
|
||||||
|
isShowActionButtons: true,
|
||||||
|
onCancelTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
onConfirmTap: () async {
|
||||||
|
openAppSettings();
|
||||||
|
}),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
backgroundColor: AppColors.infoColor,
|
||||||
|
borderColor: AppColors.infoColor,
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
borderRadius: 12,
|
||||||
|
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||||
|
height: 50.h,
|
||||||
|
icon: AppAssets.appointment_pay_icon,
|
||||||
|
iconColor: AppColors.whiteColor,
|
||||||
|
iconSize: 18.h,
|
||||||
|
).paddingSymmetrical(24.h, 24.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> askVideoCallPermission() async {
|
||||||
|
Map<Permission, PermissionStatus> statuses = await [
|
||||||
|
Permission.camera,
|
||||||
|
Permission.microphone,
|
||||||
|
].request();
|
||||||
|
|
||||||
|
if (statuses[Permission.camera] == PermissionStatus.granted && statuses[Permission.microphone] == PermissionStatus.granted) {
|
||||||
|
// Camera permission granted
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!(await Permission.camera.request().isGranted) || !(await Permission.microphone.request().isGranted)) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
String getLiveCareType(int callType) {
|
||||||
|
switch (callType) {
|
||||||
|
case 1:
|
||||||
|
return "Video Call".needTranslation;
|
||||||
|
case 2:
|
||||||
|
return "Audio Call".needTranslation;
|
||||||
|
case 3:
|
||||||
|
return "Phone Call".needTranslation;
|
||||||
|
default:
|
||||||
|
return "Video Call".needTranslation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,519 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:developer';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/api_consts.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/cache_consts.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/date_util.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.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_appointments/my_appointments_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
||||||
|
import 'package:hmg_patient_app_new/services/cache_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/common_bottom_sheet.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/in_app_browser/InAppBrowser.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:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smooth_corner/smooth_corner.dart';
|
||||||
|
|
||||||
|
class ImmediateLiveCarePaymentPage extends StatefulWidget {
|
||||||
|
ImmediateLiveCarePaymentPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ImmediateLiveCarePaymentPage> createState() => _ImmediateLiveCarePaymentPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ImmediateLiveCarePaymentPageState extends State<ImmediateLiveCarePaymentPage> {
|
||||||
|
late PayfortViewModel payfortViewModel;
|
||||||
|
late ImmediateLiveCareViewModel immediateLiveCareViewModel;
|
||||||
|
late MyAppointmentsViewModel myAppointmentsViewModel;
|
||||||
|
late AppState appState;
|
||||||
|
|
||||||
|
MyInAppBrowser? browser;
|
||||||
|
String selectedPaymentMethod = "";
|
||||||
|
|
||||||
|
String transID = "";
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
scheduleMicrotask(() {
|
||||||
|
payfortViewModel.initPayfortViewModel();
|
||||||
|
});
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
appState = getIt.get<AppState>();
|
||||||
|
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context);
|
||||||
|
immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false);
|
||||||
|
payfortViewModel = Provider.of<PayfortViewModel>(context);
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.bgScaffoldColor,
|
||||||
|
body: Consumer<MyAppointmentsViewModel>(builder: (context, myAppointmentsVM, child) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CollapsingListView(
|
||||||
|
title: "LiveCare Payment".needTranslation,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 20.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
"Mada".needTranslation.toText16(isBold: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.h),
|
||||||
|
const Spacer(),
|
||||||
|
Transform.flip(
|
||||||
|
flipX: appState.isArabic() ? true : false,
|
||||||
|
child: Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.forward_arrow_icon,
|
||||||
|
iconColor: AppColors.blackColor,
|
||||||
|
width: 40.h,
|
||||||
|
height: 40.h,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(16.h, 16.h),
|
||||||
|
).paddingSymmetrical(24.h, 0.h).onPress(() {
|
||||||
|
selectedPaymentMethod = "MADA";
|
||||||
|
openPaymentURL("mada");
|
||||||
|
}),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 20.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
|
||||||
|
SizedBox(width: 8.h),
|
||||||
|
Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
"Visa or Mastercard".needTranslation.toText16(isBold: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.h),
|
||||||
|
const Spacer(),
|
||||||
|
Transform.flip(
|
||||||
|
flipX: appState.isArabic() ? true : false,
|
||||||
|
child: Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.forward_arrow_icon,
|
||||||
|
iconColor: AppColors.blackColor,
|
||||||
|
width: 40.h,
|
||||||
|
height: 40.h,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(16.h, 16.h),
|
||||||
|
).paddingSymmetrical(24.h, 0.h).onPress(() {
|
||||||
|
selectedPaymentMethod = "VISA";
|
||||||
|
openPaymentURL("visa");
|
||||||
|
}),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 20.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Image.asset(AppAssets.tamara_en, width: 72.h, height: 25.h),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
"Tamara".needTranslation.toText16(isBold: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.h),
|
||||||
|
const Spacer(),
|
||||||
|
Transform.flip(
|
||||||
|
flipX: appState.isArabic() ? true : false,
|
||||||
|
child: Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.forward_arrow_icon,
|
||||||
|
iconColor: AppColors.blackColor,
|
||||||
|
width: 40.h,
|
||||||
|
height: 40.h,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(16.h, 16.h),
|
||||||
|
).paddingSymmetrical(24.h, 0.h).onPress(() {
|
||||||
|
selectedPaymentMethod = "TAMARA";
|
||||||
|
openPaymentURL("tamara");
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Consumer<PayfortViewModel>(builder: (context, payfortVM, child) {
|
||||||
|
//TODO: Need to add loading state & animation for Apple Pay Configuration
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.isCash ?? true)
|
||||||
|
? Container(
|
||||||
|
height: 50.h,
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: AppColors.secondaryLightRedBorderColor,
|
||||||
|
shape: SmoothRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)),
|
||||||
|
smoothness: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
"Insurance expired or inactive".needTranslation.toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h),
|
||||||
|
CustomButton(
|
||||||
|
text: LocaleKeys.updateInsurance.tr(context: context),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
CustomPageRoute(
|
||||||
|
page: InsuranceHomePage(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
backgroundColor: AppColors.primaryRedColor,
|
||||||
|
borderColor: AppColors.secondaryLightRedBorderColor,
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
borderRadius: 8,
|
||||||
|
padding: EdgeInsets.fromLTRB(15, 0, 15, 0),
|
||||||
|
height: 30.h,
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
|
||||||
|
SizedBox(height: 17.h),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
"Amount before tax".needTranslation.toText14(isBold: true),
|
||||||
|
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.amount!.toString().toText16(isBold: true), AppColors.blackColor, 13,
|
||||||
|
isSaudiCurrency: true),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor),
|
||||||
|
Utils.getPaymentAmountWithSymbol(
|
||||||
|
immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.tax!.toString().toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
|
||||||
|
isSaudiCurrency: true),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
SizedBox(height: 17.h),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
"".needTranslation.toText14(isBold: true),
|
||||||
|
Utils.getPaymentAmountWithSymbol(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!.toString().toText24(isBold: true), AppColors.blackColor, 17,
|
||||||
|
isSaudiCurrency: true),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
Platform.isIOS
|
||||||
|
? Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.apple_pay_button,
|
||||||
|
width: 200.h,
|
||||||
|
height: 80.h,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
).paddingSymmetrical(24.h, 0.h).onPress(() {
|
||||||
|
// payfortVM.setIsApplePayConfigurationLoading(true);
|
||||||
|
if (Utils.havePrivilege(103)) {
|
||||||
|
startApplePay();
|
||||||
|
} else {
|
||||||
|
openPaymentURL("ApplePay");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
: SizedBox(height: 12.h),
|
||||||
|
SizedBox(height: 12.h),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBrowserLoadStart(String url) {
|
||||||
|
print("onBrowserLoadStart");
|
||||||
|
print(url);
|
||||||
|
|
||||||
|
if (selectedPaymentMethod == "tamara") {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
Uri uri = new Uri.dataFromString(url);
|
||||||
|
// tamaraPaymentStatus = uri.queryParameters['status']!;
|
||||||
|
// tamaraOrderID = uri.queryParameters['AuthorizePaymentId']!;
|
||||||
|
} else {
|
||||||
|
Uri uri = new Uri.dataFromString(url);
|
||||||
|
// tamaraPaymentStatus = uri.queryParameters['paymentStatus']!;
|
||||||
|
// tamaraOrderID = uri.queryParameters['orderId']!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(selectedPaymentMethod != "TAMARA") {
|
||||||
|
MyInAppBrowser.successURLS.forEach((element) {
|
||||||
|
if (url.contains(element)) {
|
||||||
|
browser?.close();
|
||||||
|
MyInAppBrowser.isPaymentDone = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if(selectedPaymentMethod != "TAMARA") {
|
||||||
|
MyInAppBrowser.errorURLS.forEach((element) {
|
||||||
|
if (url.contains(element)) {
|
||||||
|
browser?.close();
|
||||||
|
MyInAppBrowser.isPaymentDone = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
onBrowserExit(bool isPaymentMade) async {
|
||||||
|
print("onBrowserExit Called!!!!");
|
||||||
|
if (selectedPaymentMethod == "TAMARA") {
|
||||||
|
// checkTamaraPaymentStatus(transID!, appo);
|
||||||
|
// if (tamaraPaymentStatus != null && tamaraPaymentStatus.toLowerCase() == "approved") {
|
||||||
|
// updateTamaraRequestStatus("success", "14", Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo), tamaraOrderID, num.parse(selectedInstallments), appo);
|
||||||
|
// } else {
|
||||||
|
// updateTamaraRequestStatus("Failed", "00", Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo), tamaraOrderID, num.parse(selectedInstallments), appo);
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
checkPaymentStatus();
|
||||||
|
// checkPaymentStatus(appo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkPaymentStatus() async {
|
||||||
|
LoaderBottomSheet.showLoader(loadingText: "Checking payment status, Please wait...".needTranslation);
|
||||||
|
await payfortViewModel.checkPaymentStatus(
|
||||||
|
transactionID: transID,
|
||||||
|
onSuccess: (apiResponse) async {
|
||||||
|
debugPrint(apiResponse.data.toString());
|
||||||
|
if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") {
|
||||||
|
await immediateLiveCareViewModel.addNewCallRequestForImmediateLiveCare(transID);
|
||||||
|
await immediateLiveCareViewModel.getPatientLiveCareHistory();
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) {
|
||||||
|
Navigator.pushAndRemoveUntil(
|
||||||
|
context,
|
||||||
|
CustomPageRoute(
|
||||||
|
page: LandingNavigation(),
|
||||||
|
),
|
||||||
|
(r) => false);
|
||||||
|
Navigator.of(context).push(
|
||||||
|
CustomPageRoute(
|
||||||
|
page: ImmediateLiveCarePendingRequestPage(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Utils.getErrorWidget(loadingText: "Unknown error occurred...".needTranslation),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openPaymentURL(String paymentMethod) {
|
||||||
|
browser = MyInAppBrowser(onExitCallback: onBrowserExit, onLoadStartCallback: onBrowserLoadStart, context: context);
|
||||||
|
transID = Utils.getAppointmentTransID(
|
||||||
|
immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceID!,
|
||||||
|
ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? 15 : 12,
|
||||||
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO: Need to pass dynamic params to the payment request instead of static values
|
||||||
|
browser?.openPaymentBrowser(
|
||||||
|
num.parse(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!),
|
||||||
|
"LiveCare Payment",
|
||||||
|
transID,
|
||||||
|
"12",
|
||||||
|
"CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
|
||||||
|
selectedPaymentMethod,
|
||||||
|
appState.getAuthenticatedUser()!.patientType.toString(),
|
||||||
|
"${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
|
||||||
|
appState.getAuthenticatedUser()!.patientId.toString(),
|
||||||
|
appState.getAuthenticatedUser()!,
|
||||||
|
browser!,
|
||||||
|
false,
|
||||||
|
"4",
|
||||||
|
immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceID.toString(),
|
||||||
|
context,
|
||||||
|
"3");
|
||||||
|
}
|
||||||
|
|
||||||
|
startApplePay() async {
|
||||||
|
LoaderBottomSheet.showLoader(loadingText: "Fetching Apple Pay details, Please wait...".needTranslation);
|
||||||
|
transID = Utils.getAppointmentTransID(
|
||||||
|
immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceID!,
|
||||||
|
ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? 15 : 12,
|
||||||
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
|
);
|
||||||
|
|
||||||
|
ApplePayInsertRequest applePayInsertRequest = ApplePayInsertRequest();
|
||||||
|
|
||||||
|
await payfortViewModel.getPayfortConfigurations(
|
||||||
|
serviceId: ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum(), projectId: ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? 15 : 12, integrationId: 2);
|
||||||
|
|
||||||
|
applePayInsertRequest.clientRequestID = transID;
|
||||||
|
applePayInsertRequest.clinicID = immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceID!;
|
||||||
|
|
||||||
|
applePayInsertRequest.currency = appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED";
|
||||||
|
applePayInsertRequest.customerEmail = "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com";
|
||||||
|
applePayInsertRequest.customerID = appState.getAuthenticatedUser()!.patientId.toString();
|
||||||
|
applePayInsertRequest.customerName = "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}";
|
||||||
|
|
||||||
|
applePayInsertRequest.deviceToken = await Utils.getStringFromPrefs(CacheConst.pushToken);
|
||||||
|
applePayInsertRequest.voipToken = await Utils.getStringFromPrefs(CacheConst.voipToken);
|
||||||
|
applePayInsertRequest.doctorID = 0;
|
||||||
|
applePayInsertRequest.projectID = "12";
|
||||||
|
applePayInsertRequest.serviceID = ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum().toString();
|
||||||
|
applePayInsertRequest.channelID = 3;
|
||||||
|
applePayInsertRequest.patientID = appState.getAuthenticatedUser()!.patientId.toString();
|
||||||
|
applePayInsertRequest.patientTypeID = appState.getAuthenticatedUser()!.patientType;
|
||||||
|
applePayInsertRequest.patientOutSA = appState.getAuthenticatedUser()!.outSa;
|
||||||
|
applePayInsertRequest.appointmentDate = DateUtil.convertDateToString(DateTime.now());
|
||||||
|
applePayInsertRequest.appointmentNo = 0;
|
||||||
|
applePayInsertRequest.orderDescription = "LiveCare Payment";
|
||||||
|
applePayInsertRequest.liveServiceID = immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceID!.toString();
|
||||||
|
applePayInsertRequest.latitude = "0.0";
|
||||||
|
applePayInsertRequest.longitude = "0.0";
|
||||||
|
applePayInsertRequest.amount = immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total.toString();
|
||||||
|
applePayInsertRequest.isSchedule = "0";
|
||||||
|
applePayInsertRequest.language = appState.isArabic() ? 'ar' : 'en';
|
||||||
|
applePayInsertRequest.languageID = appState.isArabic() ? 1 : 2;
|
||||||
|
applePayInsertRequest.userName = appState.getAuthenticatedUser()!.patientId;
|
||||||
|
applePayInsertRequest.responseContinueURL = "http://hmg.com/Documents/success.html";
|
||||||
|
applePayInsertRequest.backClickUrl = "http://hmg.com/Documents/success.html";
|
||||||
|
applePayInsertRequest.paymentOption = "ApplePay";
|
||||||
|
|
||||||
|
applePayInsertRequest.isMobSDK = true;
|
||||||
|
applePayInsertRequest.merchantReference = transID;
|
||||||
|
applePayInsertRequest.merchantIdentifier = payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier;
|
||||||
|
applePayInsertRequest.commandType = "PURCHASE";
|
||||||
|
applePayInsertRequest.signature = payfortViewModel.payfortProjectDetailsRespModel!.signature;
|
||||||
|
applePayInsertRequest.accessCode = payfortViewModel.payfortProjectDetailsRespModel!.accessCode;
|
||||||
|
applePayInsertRequest.shaRequestPhrase = payfortViewModel.payfortProjectDetailsRespModel!.shaRequest;
|
||||||
|
applePayInsertRequest.shaResponsePhrase = payfortViewModel.payfortProjectDetailsRespModel!.shaResponse;
|
||||||
|
applePayInsertRequest.returnURL = "";
|
||||||
|
|
||||||
|
//TODO: Need to pass dynamic params to the Apple Pay instead of static values
|
||||||
|
await payfortViewModel.applePayRequestInsert(applePayInsertRequest: applePayInsertRequest).then((value) {
|
||||||
|
payfortViewModel.paymentWithApplePay(
|
||||||
|
customerName: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
|
||||||
|
// customerEmail: projectViewModel.authenticatedUserObject.user.emailAddress,
|
||||||
|
customerEmail: "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
|
||||||
|
orderDescription: "LiveCare Payment",
|
||||||
|
orderAmount: double.parse(immediateLiveCareViewModel.liveCareImmediateAppointmentFeesList.total!),
|
||||||
|
merchantReference: transID,
|
||||||
|
merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier,
|
||||||
|
applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode,
|
||||||
|
applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest,
|
||||||
|
currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
|
||||||
|
onFailed: (failureResult) async {
|
||||||
|
log("failureResult: ${failureResult.message.toString()}");
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onSucceeded: (successResult) async {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
log("successResult: ${successResult.responseMessage.toString()}");
|
||||||
|
selectedPaymentMethod = successResult.paymentOption ?? "VISA";
|
||||||
|
checkPaymentStatus();
|
||||||
|
},
|
||||||
|
// projectId: appo.projectID,
|
||||||
|
// serviceTypeEnum: ServiceTypeEnum.appointmentPayment,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,305 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
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/immediate_livecare/immediate_livecare_view_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/appbar/collapsing_list_view.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:lottie/lottie.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class ImmediateLiveCarePendingRequestPage extends StatefulWidget {
|
||||||
|
ImmediateLiveCarePendingRequestPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ImmediateLiveCarePendingRequestPage> createState() => _ImmediateLiveCarePendingRequestPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ImmediateLiveCarePendingRequestPageState extends State<ImmediateLiveCarePendingRequestPage> {
|
||||||
|
late ImmediateLiveCareViewModel immediateLiveCareViewModel;
|
||||||
|
|
||||||
|
late AppState appState;
|
||||||
|
|
||||||
|
static Duration countdownDuration = Duration(minutes: 1, seconds: 0);
|
||||||
|
ValueNotifier<Duration> durationNotifier = ValueNotifier<Duration>(countdownDuration);
|
||||||
|
Timer? timer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
scheduleMicrotask(() {
|
||||||
|
countdownDuration = Duration(minutes: immediateLiveCareViewModel.patientLiveCareHistoryList[0].watingtimeInteger!, seconds: 0);
|
||||||
|
durationNotifier = ValueNotifier<Duration>(countdownDuration);
|
||||||
|
startTimer();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
timer?.cancel();
|
||||||
|
durationNotifier.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false);
|
||||||
|
appState = getIt.get<AppState>();
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.bgScaffoldColor,
|
||||||
|
body: Consumer<ImmediateLiveCareViewModel>(builder: (context, immediateLiveCareVM, child) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CollapsingListView(
|
||||||
|
title: "LiveCare Pending Request".needTranslation,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(24.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 20.h,
|
||||||
|
hasShadow: false,
|
||||||
|
side: BorderSide(color: AppColors.ratingColorYellow, width: 3.h),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.h),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"Expected waiting time: ".toText16(isBold: true),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
ValueListenableBuilder<Duration>(
|
||||||
|
valueListenable: durationNotifier,
|
||||||
|
builder: (context, duration, child) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
buildTime(duration),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 20.h,
|
||||||
|
hasShadow: false,
|
||||||
|
side: BorderSide(color: AppColors.ratingColorYellow, width: 3.h),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.h),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
AppCustomChipWidget(
|
||||||
|
labelText: immediateLiveCareViewModel.patientLiveCareHistoryList[0].stringCallStatus,
|
||||||
|
backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.20),
|
||||||
|
textColor: AppColors.alertColor,
|
||||||
|
),
|
||||||
|
Utils.buildSvgWithAssets(icon: AppAssets.waiting_icon, width: 24.h, height: 24.h),
|
||||||
|
// Lottie.asset(AppAnimations.pending_loading_animation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 80.h, height: 80.h, fit: BoxFit.cover),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
"Hala ${appState.getAuthenticatedUser()!.firstName}!!!".needTranslation.toText16(isBold: true),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
AppCustomChipWidget(
|
||||||
|
icon: AppAssets.appointment_calendar_icon,
|
||||||
|
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(immediateLiveCareViewModel.patientLiveCareHistoryList[0].arrivalTime), false)),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
"Your turn is after ${immediateLiveCareViewModel.patientLiveCareHistoryList[0].patCount} patients.".toText16(isBold: true),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: true,
|
||||||
|
),
|
||||||
|
child: CustomButton(
|
||||||
|
text: "Call LiveCare Support".needTranslation,
|
||||||
|
onPressed: () async {
|
||||||
|
launchUrl(Uri.parse("tel://" + "011 525 9553"));
|
||||||
|
},
|
||||||
|
backgroundColor: AppColors.primaryRedColor,
|
||||||
|
borderColor: AppColors.primaryRedColor,
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
borderRadius: 12,
|
||||||
|
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||||
|
height: 50.h,
|
||||||
|
icon: AppAssets.call_fill,
|
||||||
|
iconColor: AppColors.whiteColor,
|
||||||
|
iconSize: 21.h,
|
||||||
|
).paddingSymmetrical(24.h, 24.h),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void startTimer() {
|
||||||
|
timer = Timer.periodic(const Duration(seconds: 1), (_) => addTime());
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTime() {
|
||||||
|
final seconds = durationNotifier.value.inSeconds - 1;
|
||||||
|
if (seconds < 0) {
|
||||||
|
timer?.cancel();
|
||||||
|
// Handle end of timer here
|
||||||
|
// showEndMessage();
|
||||||
|
} else {
|
||||||
|
durationNotifier.value = Duration(seconds: seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _onWillPop() async {
|
||||||
|
timer?.cancel();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildTime(Duration duration) {
|
||||||
|
String twoDigits(int n) => n.toString().padLeft(2, '0');
|
||||||
|
final hours = twoDigits(duration.inHours);
|
||||||
|
final minutes = twoDigits(duration.inMinutes.remainder(60));
|
||||||
|
final seconds = twoDigits(duration.inSeconds.remainder(60));
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
buildTimeColumn(hours, "Hours".needTranslation),
|
||||||
|
buildTimeColumn(minutes, "Mins".needTranslation),
|
||||||
|
buildTimeColumn(seconds, "Secs".needTranslation, isLast: true),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildTimeColumn(String time, String label, {bool isLast = false}) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
buildDigit(time[0]),
|
||||||
|
buildDigit(time[1]),
|
||||||
|
if (!isLast) buildTimeSeparator(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
buildLabel(label),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildDigit(String digit) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||||
|
// margin: const EdgeInsets.symmetric(horizontal: 2),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: ClipRect(
|
||||||
|
child: AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 600),
|
||||||
|
switchInCurve: Curves.easeOutExpo,
|
||||||
|
switchOutCurve: Curves.easeInExpo,
|
||||||
|
transitionBuilder: (Widget child, Animation<double> animation) {
|
||||||
|
return Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
SlideTransition(
|
||||||
|
position: Tween<Offset>(
|
||||||
|
begin: const Offset(0, -1),
|
||||||
|
end: const Offset(0, 1),
|
||||||
|
).animate(CurvedAnimation(
|
||||||
|
parent: animation,
|
||||||
|
curve: Curves.easeOutCubic,
|
||||||
|
)),
|
||||||
|
child: FadeTransition(
|
||||||
|
opacity: animation,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SlideTransition(
|
||||||
|
position: Tween<Offset>(
|
||||||
|
begin: const Offset(0, -1),
|
||||||
|
end: const Offset(0, 0),
|
||||||
|
).animate(CurvedAnimation(
|
||||||
|
parent: animation,
|
||||||
|
curve: Curves.bounceIn,
|
||||||
|
)),
|
||||||
|
child: FadeTransition(
|
||||||
|
opacity: animation,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
digit,
|
||||||
|
key: ValueKey<String>(digit),
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 20.fSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildLabel(String label) {
|
||||||
|
return label.toText14(isBold: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildTimeSeparator() {
|
||||||
|
return const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 2.0),
|
||||||
|
child: Text(
|
||||||
|
":",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,173 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_staggered_animations/flutter_staggered_animations.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/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/book_appointments/book_appointments_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_clinic_list_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/get_livecare_clinics_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_clinics_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/widgets/select_livecare_call_type.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/clinic_card.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/widgets/livecare_clinic_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/loader/bottomsheet_loader.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class SelectImmediateLiveCareClinicPage extends StatefulWidget {
|
||||||
|
const SelectImmediateLiveCareClinicPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SelectImmediateLiveCareClinicPage> createState() => _SelectImmediateLiveCareClinicPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SelectImmediateLiveCareClinicPageState extends State<SelectImmediateLiveCareClinicPage> {
|
||||||
|
TextEditingController searchEditingController = TextEditingController();
|
||||||
|
FocusNode textFocusNode = FocusNode();
|
||||||
|
late AppState appState;
|
||||||
|
late ImmediateLiveCareViewModel immediateLiveCareViewModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
scheduleMicrotask(() {
|
||||||
|
immediateLiveCareViewModel.getLiveCareImmediateClinicsList();
|
||||||
|
immediateLiveCareViewModel.setLiveCareSelectedCallType(0);
|
||||||
|
});
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
textFocusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
immediateLiveCareViewModel = Provider.of<ImmediateLiveCareViewModel>(context, listen: false);
|
||||||
|
appState = getIt.get<AppState>();
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.bgScaffoldColor,
|
||||||
|
body: CollapsingListView(
|
||||||
|
title: "Select LiveCare Clinic".needTranslation,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(24.h),
|
||||||
|
child: Consumer<ImmediateLiveCareViewModel>(builder: (context, immediateLiveCareVM, child) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
// SizedBox(height: 16.h),
|
||||||
|
// TextInputWidget(
|
||||||
|
// labelText: LocaleKeys.search.tr(context: context),
|
||||||
|
// hintText: LocaleKeys.clinicName.tr(context: context),
|
||||||
|
// controller: searchEditingController,
|
||||||
|
// isEnable: true,
|
||||||
|
// prefix: null,
|
||||||
|
// autoFocus: false,
|
||||||
|
// isBorderAllowed: false,
|
||||||
|
// keyboardType: TextInputType.text,
|
||||||
|
// focusNode: textFocusNode,
|
||||||
|
// suffix: searchEditingController.text.isNotEmpty
|
||||||
|
// ? GestureDetector(
|
||||||
|
// onTap: () {
|
||||||
|
// searchEditingController.clear();
|
||||||
|
// bookAppointmentsViewModel.filterClinics("");
|
||||||
|
// textFocusNode.unfocus();
|
||||||
|
// },
|
||||||
|
// child: Utils.buildSvgWithAssets(icon: AppAssets.close_bottom_sheet_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown),
|
||||||
|
// )
|
||||||
|
// : null,
|
||||||
|
// onChange: (value) {
|
||||||
|
// bookAppointmentsViewModel.filterClinics(value!);
|
||||||
|
// },
|
||||||
|
// padding: EdgeInsets.symmetric(
|
||||||
|
// vertical: ResponsiveExtension(10).h,
|
||||||
|
// horizontal: ResponsiveExtension(15).h,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
ListView.separated(
|
||||||
|
padding: EdgeInsets.only(top: 16.h),
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: immediateLiveCareVM.isImmediateLiveCareClinicsLoading ? 5 : immediateLiveCareVM.immediateLiveCareClinicsList.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return immediateLiveCareVM.isImmediateLiveCareClinicsLoading
|
||||||
|
? ClinicCard(
|
||||||
|
bookAppointmentsVM: getIt.get<BookAppointmentsViewModel>(),
|
||||||
|
liveCareClinicsResponseModel: GetLiveCareClinicsResponseModel(),
|
||||||
|
clinicsListResponseModel: GetClinicsListResponseModel(),
|
||||||
|
isLoading: immediateLiveCareVM.isImmediateLiveCareClinicsLoading,
|
||||||
|
)
|
||||||
|
: 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,
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
|
||||||
|
child: LiveCareClinicCard(
|
||||||
|
immediateLiveCareViewModel: immediateLiveCareVM,
|
||||||
|
liveCareClinicListResponseModel: immediateLiveCareVM.immediateLiveCareClinicsList[index],
|
||||||
|
isLoading: immediateLiveCareVM.isImmediateLiveCareClinicsLoading,
|
||||||
|
).onPress(() {
|
||||||
|
onImmediateLiveCareClinicSelected(immediateLiveCareVM.immediateLiveCareClinicsList[index]);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onImmediateLiveCareClinicSelected(GetLiveCareClinicListResponseModel liveCareClinic) {
|
||||||
|
//TODO: add implementation to show clinic schedule
|
||||||
|
if (liveCareClinic.isOnline == 1) {
|
||||||
|
showCommonBottomSheetWithoutHeight(context, child: SelectLiveCareCallType(immediateLiveCareViewModel: immediateLiveCareViewModel), callBackFunc: () async {
|
||||||
|
if (immediateLiveCareViewModel.liveCareSelectedCallType != 0) {
|
||||||
|
immediateLiveCareViewModel.setImmediateLiveCareSelectedClinic(liveCareClinic);
|
||||||
|
LoaderBottomSheet.showLoader(loadingText: "Fetching fees, Please wait...".needTranslation);
|
||||||
|
await immediateLiveCareViewModel.getLiveCareImmediateAppointmentFees(onSuccess: (val) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
Navigator.of(context).push(
|
||||||
|
CustomPageRoute(
|
||||||
|
page: ImmediateLiveCarePaymentDetails(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}, onError: (err) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, title: "Select LiveCare call type".needTranslation, isCloseButtonVisible: true, isFullScreen: false);
|
||||||
|
} else {
|
||||||
|
showCommonBottomSheetWithoutHeight(context,
|
||||||
|
child: Utils.getErrorWidget(
|
||||||
|
loadingText: "The selected clinic is only available between ${liveCareClinic.shiftTimings!.first.startTime} & ${liveCareClinic.shiftTimings!.first.endTime} hours.".needTranslation),
|
||||||
|
callBackFunc: () {},
|
||||||
|
title: "",
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
isFullScreen: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
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/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/book_appointments/book_appointments_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/models/resp_models/get_livecare_immediate_clinics_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
|
||||||
|
class LiveCareClinicCard extends StatelessWidget {
|
||||||
|
LiveCareClinicCard({super.key, required this.liveCareClinicListResponseModel, required this.isLoading, required this.immediateLiveCareViewModel});
|
||||||
|
|
||||||
|
GetLiveCareClinicListResponseModel liveCareClinicListResponseModel;
|
||||||
|
bool isLoading;
|
||||||
|
ImmediateLiveCareViewModel immediateLiveCareViewModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
AppState appState = getIt.get<AppState>();
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.all(16.h),
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||||
|
Utils.buildSvgWithAssets(icon: AppAssets.generic_clinic_icon, width: 24.h, height: 24.h, fit: BoxFit.contain).toShimmer2(isShow: isLoading),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.livecare_online_icon,
|
||||||
|
width: 16.h,
|
||||||
|
height: 16.h,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
iconColor: liveCareClinicListResponseModel.isOnline == 1 ? AppColors.successColor : AppColors.primaryRedColor)
|
||||||
|
.toShimmer2(isShow: isLoading),
|
||||||
|
SizedBox(height: 4.h),
|
||||||
|
liveCareClinicListResponseModel.isOnline == 1
|
||||||
|
? LocaleKeys.online.tr(context: context).toText10(isBold: true, color: AppColors.successColor).toShimmer2(isShow: isLoading)
|
||||||
|
: "Offline".toText10(isBold: true, color: AppColors.primaryRedColor).toShimmer2(isShow: isLoading),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||||
|
Expanded(
|
||||||
|
child: (isLoading ? "Cardiology" : (appState.isArabic() ? liveCareClinicListResponseModel.serviceNameN : liveCareClinicListResponseModel.serviceName))!
|
||||||
|
.toText16(isBold: true)
|
||||||
|
.toShimmer2(isShow: isLoading)),
|
||||||
|
Transform.flip(
|
||||||
|
flipX: appState.isArabic() ? true : false,
|
||||||
|
child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 40.h, height: 40.h, fit: BoxFit.contain, iconColor: AppColors.textColor).toShimmer2(isShow: isLoading)),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/utils/size_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/book_appointments/book_appointments_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_file_card.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
|
||||||
|
class SelectLiveCareCallType extends StatelessWidget {
|
||||||
|
SelectLiveCareCallType({super.key, required this.immediateLiveCareViewModel});
|
||||||
|
|
||||||
|
ImmediateLiveCareViewModel immediateLiveCareViewModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
//TODO: Replace with actual icons
|
||||||
|
return GridView(
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 3,
|
||||||
|
crossAxisSpacing: 16,
|
||||||
|
mainAxisSpacing: 16,
|
||||||
|
mainAxisExtent: 130,
|
||||||
|
),
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
shrinkWrap: true,
|
||||||
|
children: [
|
||||||
|
MedicalFileCard(
|
||||||
|
label: "Video Call".needTranslation,
|
||||||
|
textColor: AppColors.blackColor,
|
||||||
|
backgroundColor: AppColors.whiteColor,
|
||||||
|
svgIcon: AppAssets.eye_result_icon,
|
||||||
|
isLargeText: true,
|
||||||
|
iconSize: 36.h,
|
||||||
|
).onPress(() {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
immediateLiveCareViewModel.setLiveCareSelectedCallType(1);
|
||||||
|
}),
|
||||||
|
MedicalFileCard(
|
||||||
|
label: "Audio Call".needTranslation,
|
||||||
|
textColor: AppColors.blackColor,
|
||||||
|
backgroundColor: AppColors.whiteColor,
|
||||||
|
svgIcon: AppAssets.allergy_info_icon,
|
||||||
|
isLargeText: true,
|
||||||
|
iconSize: 36.h,
|
||||||
|
).onPress(() {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
immediateLiveCareViewModel.setLiveCareSelectedCallType(2);
|
||||||
|
}),
|
||||||
|
MedicalFileCard(
|
||||||
|
label: "Phone Call".needTranslation,
|
||||||
|
textColor: AppColors.blackColor,
|
||||||
|
backgroundColor: AppColors.whiteColor,
|
||||||
|
svgIcon: AppAssets.vaccine_info_icon,
|
||||||
|
isLargeText: true,
|
||||||
|
iconSize: 36.h,
|
||||||
|
).onPress(() {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
immediateLiveCareViewModel.setLiveCareSelectedCallType(3);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,94 +0,0 @@
|
|||||||
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/extensions/string_extensions.dart';
|
|
||||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.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/patient_medical_response_model.dart';
|
|
||||||
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
|
||||||
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/patient_medical_report_card.dart';
|
|
||||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
|
||||||
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
class MedicalReportsPage extends StatefulWidget {
|
|
||||||
const MedicalReportsPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<MedicalReportsPage> createState() => _MedicalReportsPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MedicalReportsPageState extends State<MedicalReportsPage> {
|
|
||||||
late MedicalFileViewModel medicalFileViewModel;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: AppColors.bgScaffoldColor,
|
|
||||||
body: CollapsingListView(
|
|
||||||
title: "Medical Reports".needTranslation,
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(height: 16.h),
|
|
||||||
CustomTabBar(
|
|
||||||
activeTextColor: Color(0xffED1C2B),
|
|
||||||
activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
|
|
||||||
tabs: [
|
|
||||||
CustomTabBarModel(null, "Requested".needTranslation),
|
|
||||||
CustomTabBarModel(null, "Ready".needTranslation),
|
|
||||||
CustomTabBarModel(null, "Cancelled".needTranslation),
|
|
||||||
],
|
|
||||||
onTabChange: (index) {
|
|
||||||
medicalFileViewModel.onMedicalReportTabChange(index);
|
|
||||||
},
|
|
||||||
).paddingSymmetrical(24.h, 0.h),
|
|
||||||
Consumer<MedicalFileViewModel>(builder: (context, medicalFileVM, child) {
|
|
||||||
return ListView.separated(
|
|
||||||
padding: EdgeInsets.only(top: 24.h),
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: NeverScrollableScrollPhysics(),
|
|
||||||
itemCount: medicalFileViewModel.isPatientMedicalReportsListLoading ? 3 : medicalFileViewModel.patientMedicalReportList.length,
|
|
||||||
// medicalFileViewModel.patientMedicalReportList.isNotEmpty
|
|
||||||
// ? medicalFileViewModel.patientMedicalReportList.length
|
|
||||||
// : 1,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return medicalFileViewModel.isPatientMedicalReportsListLoading
|
|
||||||
? PatientMedicalReportCard(
|
|
||||||
patientMedicalReportResponseModel: PatientMedicalReportResponseModel(),
|
|
||||||
medicalFileViewModel: medicalFileVM,
|
|
||||||
isLoading: true,
|
|
||||||
).paddingSymmetrical(24.h, 0.h)
|
|
||||||
: 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,
|
|
||||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
|
|
||||||
child: PatientMedicalReportCard(
|
|
||||||
patientMedicalReportResponseModel: medicalFileVM.patientMedicalReportList[index],
|
|
||||||
medicalFileViewModel: medicalFileVM,
|
|
||||||
|
|
||||||
isLoading: false,
|
|
||||||
),
|
|
||||||
).paddingSymmetrical(24.h, 0.h),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
SizedBox(height: 24.h),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
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/extensions/string_extensions.dart';
|
||||||
|
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_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:provider/provider.dart';
|
||||||
|
|
||||||
|
class MedicalReportRequestPage extends StatelessWidget {
|
||||||
|
MedicalReportRequestPage({super.key});
|
||||||
|
|
||||||
|
late MedicalFileViewModel medicalFileViewModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
|
||||||
|
return CollapsingListView(
|
||||||
|
title: "Medical Reports".needTranslation,
|
||||||
|
isClose: true,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
ListView.separated(
|
||||||
|
padding: EdgeInsets.only(top: 24.h),
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: medicalFileViewModel.patientMedicalReportAppointmentHistoryList.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return 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,
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
|
||||||
|
child: AppointmentCard(
|
||||||
|
patientAppointmentHistoryResponseModel: medicalFileViewModel.patientMedicalReportAppointmentHistoryList[index],
|
||||||
|
myAppointmentsViewModel: Provider.of<MyAppointmentsViewModel>(context, listen: false),
|
||||||
|
medicalFileViewModel: medicalFileViewModel,
|
||||||
|
isLoading: false,
|
||||||
|
isFromHomePage: false,
|
||||||
|
isFromMedicalReport: true,
|
||||||
|
),
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
|
||||||
|
),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,240 @@
|
|||||||
|
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/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/medical_file/medical_file_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/medical_file/models/patient_medical_response_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/medical_report/medical_report_request_page.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/medical_report/widgets/patient_medical_report_card.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/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:provider/provider.dart';
|
||||||
|
|
||||||
|
class MedicalReportsPage extends StatefulWidget {
|
||||||
|
const MedicalReportsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MedicalReportsPage> createState() => _MedicalReportsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MedicalReportsPageState extends State<MedicalReportsPage> {
|
||||||
|
late MedicalFileViewModel medicalFileViewModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.bgScaffoldColor,
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CollapsingListView(
|
||||||
|
title: "Medical Reports".needTranslation,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Consumer<MedicalFileViewModel>(builder: (context, medicalFileVM, child) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
CustomButton(
|
||||||
|
text: "Requested".needTranslation,
|
||||||
|
onPressed: () {
|
||||||
|
medicalFileViewModel.onMedicalReportTabChange(0);
|
||||||
|
},
|
||||||
|
backgroundColor: medicalFileVM.selectedMedicalReportsTabIndex == 0 ? AppColors.bgRedLightColor : AppColors.whiteColor,
|
||||||
|
borderColor: medicalFileVM.selectedMedicalReportsTabIndex == 0 ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
|
||||||
|
textColor: medicalFileVM.selectedMedicalReportsTabIndex == 0 ? AppColors.primaryRedColor : AppColors.blackColor,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||||
|
height: 40.h,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.h),
|
||||||
|
CustomButton(
|
||||||
|
text: LocaleKeys.ready.tr(context: context),
|
||||||
|
onPressed: () {
|
||||||
|
medicalFileViewModel.onMedicalReportTabChange(1);
|
||||||
|
},
|
||||||
|
backgroundColor: medicalFileVM.selectedMedicalReportsTabIndex == 1 ? AppColors.bgRedLightColor : AppColors.whiteColor,
|
||||||
|
borderColor: medicalFileVM.selectedMedicalReportsTabIndex == 1 ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
|
||||||
|
textColor: medicalFileVM.selectedMedicalReportsTabIndex == 1 ? AppColors.primaryRedColor : AppColors.blackColor,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||||
|
height: 40.h,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.h),
|
||||||
|
CustomButton(
|
||||||
|
text: LocaleKeys.cancelled.tr(context: context),
|
||||||
|
onPressed: () {
|
||||||
|
medicalFileViewModel.onMedicalReportTabChange(2);
|
||||||
|
},
|
||||||
|
backgroundColor: medicalFileVM.selectedMedicalReportsTabIndex == 2 ? AppColors.bgRedLightColor : AppColors.whiteColor,
|
||||||
|
borderColor: medicalFileVM.selectedMedicalReportsTabIndex == 2 ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
|
||||||
|
textColor: medicalFileVM.selectedMedicalReportsTabIndex == 2 ? AppColors.primaryRedColor : AppColors.blackColor,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||||
|
height: 40.h,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
// CustomTabBar(
|
||||||
|
// activeTextColor: Color(0xffED1C2B),
|
||||||
|
// activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
|
||||||
|
// tabs: [
|
||||||
|
// CustomTabBarModel(null, "Requested".needTranslation),
|
||||||
|
// CustomTabBarModel(null, "Ready".needTranslation),
|
||||||
|
// CustomTabBarModel(null, "Cancelled".needTranslation),
|
||||||
|
// ],
|
||||||
|
// onTabChange: (index) {
|
||||||
|
// medicalFileViewModel.onMedicalReportTabChange(index);
|
||||||
|
// },
|
||||||
|
// ).paddingSymmetrical(24.h, 0.h),
|
||||||
|
ListView.separated(
|
||||||
|
padding: EdgeInsets.only(top: 24.h),
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: medicalFileViewModel.isPatientMedicalReportsListLoading
|
||||||
|
? 3
|
||||||
|
: medicalFileViewModel.patientMedicalReportList.isNotEmpty
|
||||||
|
? medicalFileViewModel.patientMedicalReportList.length
|
||||||
|
: 1,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return medicalFileViewModel.isPatientMedicalReportsListLoading
|
||||||
|
? PatientMedicalReportCard(
|
||||||
|
patientMedicalReportResponseModel: PatientMedicalReportResponseModel(),
|
||||||
|
medicalFileViewModel: medicalFileVM,
|
||||||
|
isLoading: true,
|
||||||
|
).paddingSymmetrical(24.h, 0.h)
|
||||||
|
: medicalFileViewModel.patientMedicalReportList.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,
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
|
||||||
|
child: PatientMedicalReportCard(
|
||||||
|
patientMedicalReportResponseModel: medicalFileVM.patientMedicalReportList[index],
|
||||||
|
medicalFileViewModel: medicalFileVM,
|
||||||
|
isLoading: false,
|
||||||
|
),
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Utils.getNoDataWidget(context, noDataText: "You don't have any medical reports yet.".needTranslation).paddingSymmetrical(24.h, 24.h);
|
||||||
|
},
|
||||||
|
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
|
||||||
|
),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: true,
|
||||||
|
),
|
||||||
|
child: CustomButton(
|
||||||
|
text: "Request medical report".needTranslation,
|
||||||
|
onPressed: () async {
|
||||||
|
LoaderBottomSheet.showLoader();
|
||||||
|
await medicalFileViewModel.getPatientMedicalReportAppointmentsList(onSuccess: (val) async {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
bool? value = await Navigator.of(context).push(
|
||||||
|
CustomPageRoute(
|
||||||
|
page: MedicalReportRequestPage(),
|
||||||
|
fullScreenDialog: true,
|
||||||
|
direction: AxisDirection.down,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (value != null) {
|
||||||
|
showConfirmRequestMedicalReportBottomSheet();
|
||||||
|
}
|
||||||
|
}, onError: (err) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Utils.getErrorWidget(loadingText: "You do not have any appointments to request a medical report.".needTranslation),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
backgroundColor: AppColors.primaryRedColor,
|
||||||
|
borderColor: AppColors.primaryRedColor,
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
borderRadius: 12,
|
||||||
|
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||||
|
height: 45.h,
|
||||||
|
icon: AppAssets.requests,
|
||||||
|
iconColor: AppColors.whiteColor,
|
||||||
|
iconSize: 20.h,
|
||||||
|
).paddingSymmetrical(24.h, 24.h),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showConfirmRequestMedicalReportBottomSheet() {
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
title: LocaleKeys.notice.tr(context: context),
|
||||||
|
context,
|
||||||
|
child: Utils.getWarningWidget(
|
||||||
|
loadingText: "Are you sure you want to request a medical report for this appointment?".needTranslation,
|
||||||
|
isShowActionButtons: true,
|
||||||
|
onCancelTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
onConfirmTap: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
LoaderBottomSheet.showLoader();
|
||||||
|
await medicalFileViewModel.insertRequestForMedicalReport(onSuccess: (val) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
showCommonBottomSheetWithoutHeight(context, child: Utils.getSuccessWidget(loadingText: "Your medical report request has been successfully submitted.".needTranslation), callBackFunc: () {
|
||||||
|
medicalFileViewModel.setIsPatientMedicalReportsLoading(true);
|
||||||
|
medicalFileViewModel.onMedicalReportTabChange(0);
|
||||||
|
medicalFileViewModel.getPatientMedicalReportList();
|
||||||
|
});
|
||||||
|
}, onError: (err) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
showCommonBottomSheetWithoutHeight(context, child: Utils.getErrorWidget(loadingText: err), callBackFunc: () {
|
||||||
|
medicalFileViewModel.setIsPatientMedicalReportsLoading(true);
|
||||||
|
medicalFileViewModel.onMedicalReportTabChange(0);
|
||||||
|
medicalFileViewModel.getPatientMedicalReportList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue