diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index df81621..da78824 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; @@ -361,6 +362,21 @@ class DashboardApiClient { ); } + Future getENSATItgToken() async { + String url = "${ApiConsts.cocRest}Mohemm_ENSAT_GetItgToken"; + + Map postParams = {"EmployeeNumber": AppState().getUserName}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.Mohemm_ENSAT_GetItgToken_Response; + }, + url, + postParams, + ); + } + //Submit ITG Future submitItgForm({required String comment, required String masterId, required List> itgList, required int serviceId}) async { String url = "${ApiConsts.cocRest}Mohemm_ITG_Survey_Response"; @@ -442,7 +458,7 @@ class DashboardApiClient { postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject( (json) { - GetEmployeeParking responseData = GetEmployeeParking.fromJson(json); + GetEmployeeParking responseData = GetEmployeeParking.fromJson(json); return responseData; }, url, @@ -452,16 +468,14 @@ class DashboardApiClient { //Fetch All Courses Status Future fetchAllCoursesStatus() async { - String url = ApiConsts.eLearningBaseUrl +"Fetch_All_Courses_Status.php"; + String url = ApiConsts.eLearningBaseUrl + "Fetch_All_Courses_Status.php"; Map headers = { 'x-api-key': 'bLi@mbXJeXTHd/)h&LFh%25+%25(Nbnaq6hBg%7d%5dyQbthY%7bv6ew6-5UT\$NASwucn%7d,_PSJpuwNCCen2%7djj%7b00HR2T-%5b,k7W%7d-0yepK?%258', 'Content-Type': 'application/x-www-form-urlencoded', }; - Map postParams = { - "username": AppState().memberInformationList?.eMPLOYEENUMBER ?? "", - }; + Map postParams = {"username": AppState().memberInformationList?.eMPLOYEENUMBER ?? ""}; return await ApiClient().postJsonForObject( (json) { diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index c20cdbc..7513370 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -4,12 +4,12 @@ class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server static String ssoBaseUrl = "https://sso.hmg.com"; // New Live server // // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver @@ -17,6 +17,7 @@ class ApiConsts { // static String baseUrl = "https://mohemm.hmg.com"; // New Live server //static String eLearningBaseUrl = "https://elearning.hmg.com/moodle_dev/api/"; // Elearning server UAT static String eLearningBaseUrl = "https://elearning.hmg.com/moodle/api/"; // Elearning server live + static String enSATLiveURL = "https://ensat.hmg.com/auth/autologin"; // ENSAT server live // static String baseUrl = "http://10.20.200.111:1010/"; diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index df94c8b..01e3056 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -398,6 +398,7 @@ class GenericResponseModel { bool? isActiveCode; bool? isSMSSent; PortalDirectionData? portalDirectionData; + String? Mohemm_ENSAT_GetItgToken_Response; GenericResponseModel({ this.date, @@ -669,7 +670,8 @@ class GenericResponseModel { this.ePharmacyGetItemOnHandList, this.isActiveCode, this.isSMSSent, - this.getFADisposalNtfDetails + this.getFADisposalNtfDetails, + this.Mohemm_ENSAT_GetItgToken_Response, }); GenericResponseModel.fromJson(Map json) { @@ -943,7 +945,6 @@ class GenericResponseModel { getFADisposalNtfDetails = json['GetFADisposalNtfDetails'] != null ? GetFaDisposalNtfDetails.fromJson(json['GetFADisposalNtfDetails']) : null; - if (json['GetEarningsList'] != null) { getEarningsList = []; json['GetEarningsList'].forEach((v) { @@ -1464,6 +1465,7 @@ class GenericResponseModel { ePharmacyGetItemOnHandList = json['ePharmacy_GetItemOnHandList']; isActiveCode = json['isActiveCode']; isSMSSent = json['isSMSSent']; + Mohemm_ENSAT_GetItgToken_Response = json['Mohemm_ENSAT_GetItgToken_Response']; } Map toJson() { @@ -1561,7 +1563,7 @@ class GenericResponseModel { if (this.getActionHistoryList != null) { data['GetActionHistoryList'] = this.getActionHistoryList!.map((v) => v.toJson()).toList(); } - data['GetFADisposalNtfDetails'] =this.getFADisposalNtfDetails; + data['GetFADisposalNtfDetails'] = this.getFADisposalNtfDetails; data['GetAddressDffStructureList'] = this.getAddressDffStructureList; data['GetAddressNotificationBodyList'] = this.getAddressNotificationBodyList; @@ -1949,6 +1951,7 @@ class GenericResponseModel { data['ePharmacy_GetItemOnHandList'] = this.ePharmacyGetItemOnHandList; data['isActiveCode'] = this.isActiveCode; data['isSMSSent'] = this.isSMSSent; + data['Mohemm_ENSAT_GetItgToken_Response'] = this.Mohemm_ENSAT_GetItgToken_Response; return data; } } diff --git a/lib/models/itg/itg_response_model.dart b/lib/models/itg/itg_response_model.dart index 6a85cb1..ff10908 100644 --- a/lib/models/itg/itg_response_model.dart +++ b/lib/models/itg/itg_response_model.dart @@ -12,12 +12,7 @@ MohemmItgResponseItem mohemmItgResponseItemFromJson(String str) => MohemmItgResp String mohemmItgResponseItemToJson(MohemmItgResponseItem data) => json.encode(data.toJson()); class MohemmItgResponseItem { - MohemmItgResponseItem({ - this.statusCode, - this.message, - this.originalErrMsg, - this.result, - }); + MohemmItgResponseItem({this.statusCode, this.message, this.originalErrMsg, this.result}); final int? statusCode; final dynamic? message; @@ -25,77 +20,64 @@ class MohemmItgResponseItem { final ItgResponseResult? result; factory MohemmItgResponseItem.fromJson(Map json) => MohemmItgResponseItem( - statusCode: json["statusCode"] == null ? null : json["statusCode"], - message: json["message"], - originalErrMsg: json["originalErrMsg"], - result: json["result"] == null ? null : ItgResponseResult.fromJson(json["result"]), - ); + statusCode: json["statusCode"] == null ? null : json["statusCode"], + message: json["message"], + originalErrMsg: json["originalErrMsg"], + result: json["result"] == null ? null : ItgResponseResult.fromJson(json["result"]), + ); - Map toJson() => { - "statusCode": statusCode == null ? null : statusCode, - "message": message, - "originalErrMsg": originalErrMsg, - "result": result == null ? null : result!.toJson(), - }; + Map toJson() => {"statusCode": statusCode == null ? null : statusCode, "message": message, "originalErrMsg": originalErrMsg, "result": result == null ? null : result!.toJson()}; } class ItgResponseResult { - ItgResponseResult({ - this.totalItemsCount, - this.data, - this.errormsg, - }); -// -// final dynamic totalItemsCount; -// final ItgResponseData? data; -// final dynamic errormsg; -// -// factory ItgResponseResult.fromJson(Map json) => ItgResponseResult( -// totalItemsCount: json["totalItemsCount"], -// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]), -// errormsg: json["errormsg"], -// ); -// -// Map toJson() => { -// "totalItemsCount": totalItemsCount, -// "data": data == null ? null : data!.toJson(), -// "errormsg": errormsg, -// }; -// } - -// todo these lines, for ERM new change on UAT -dynamic totalItemsCount; -List? data; -dynamic errormsg; - -ItgResponseResult.fromJson(Map json) { - totalItemsCount = json['totalItemsCount']; - if (json['data'] != null) { - data = []; - if(json['data'] is List) { - json['data'].forEach((v) { - data!.add(ItgResponseData.fromJson(v)); - }); - } else { - data!.add(ItgResponseData.fromJson(json['data'])); + ItgResponseResult({this.totalItemsCount, this.data, this.errormsg}); + + // + // final dynamic totalItemsCount; + // final ItgResponseData? data; + // final dynamic errormsg; + // + // factory ItgResponseResult.fromJson(Map json) => ItgResponseResult( + // totalItemsCount: json["totalItemsCount"], + // data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]), + // errormsg: json["errormsg"], + // ); + // + // Map toJson() => { + // "totalItemsCount": totalItemsCount, + // "data": data == null ? null : data!.toJson(), + // "errormsg": errormsg, + // }; + // } + + // todo these lines, for ERM new change on UAT + dynamic totalItemsCount; + List? data; + dynamic errormsg; + + ItgResponseResult.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + if (json['data'] != null) { + data = []; + if (json['data'] is List) { + json['data'].forEach((v) { + data!.add(ItgResponseData.fromJson(v)); + }); + } else { + data!.add(ItgResponseData.fromJson(json['data'])); + } } - + errormsg = json['errormsg']; } - errormsg = json['errormsg']; -} -// -// factory ItgResponseResult.fromJson(Map json) => ItgResponseResult( -// totalItemsCount: json["totalItemsCount"], -// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]), -// errormsg: json["errormsg"], -// ); - -Map toJson() => { - "totalItemsCount": totalItemsCount, - "data": data == null ? null : data!.map((v) => v.toJson()).toList(), - "errormsg": errormsg, - }; + // + // factory ItgResponseResult.fromJson(Map json) => ItgResponseResult( + // totalItemsCount: json["totalItemsCount"], + // data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]), + // errormsg: json["errormsg"], + // ); + + Map toJson() => {"totalItemsCount": totalItemsCount, "data": data == null ? null : data!.map((v) => v.toJson()).toList(), "errormsg": errormsg}; } class ItgResponseData { @@ -121,6 +103,7 @@ class ItgResponseData { this.pageSize, this.pageNo, this.languageId, + this.deadline, }); final String? notificationMasterId; @@ -144,52 +127,55 @@ class ItgResponseData { final dynamic pageSize; final dynamic pageNo; final dynamic languageId; + dynamic deadline; factory ItgResponseData.fromJson(Map json) => ItgResponseData( - notificationMasterId: json["notificationMasterId"] == null ? null : json["notificationMasterId"], - notificationType: json["notificationType"] == null ? null : json["notificationType"], - referenceItemId: json["referenceItemId"] == null ? null : json["referenceItemId"], - notificationTitle: json["notificationTitle"] == null ? null : json["notificationTitle"], - enableAt: json["enableAt"] == null ? null : json["enableAt"], - applicationItemId: json["applicationItemId"], - startDate: json["startDate"], - endDate: json["endDate"], - isRepeat: json["isRepeat"] == null ? null : json["isRepeat"], - channelId: json["channelId"] == null ? null : json["channelId"], - serviceId: json["serviceId"] == null ? null : json["serviceId"], - channelName: json["channelName"] == null ? null : json["channelName"], - serviceName: json["serviceName"] == null ? null : json["serviceName"], - isDeleted: json["isDeleted"] == null ? null : json["isDeleted"], - showDelete: json["showDelete"] == null ? null : json["showDelete"], - advertisement: json["advertisement"] == null ? null : Advertisement.fromJson(json["advertisement"]), - survey: json["survey"] == null ? null : SurveyModel.fromJson(json["survey"]), - isActive: json["isActive"], - pageSize: json["pageSize"], - pageNo: json["pageNo"], - languageId: json["languageId"], - ); + notificationMasterId: json["notificationMasterId"] == null ? null : json["notificationMasterId"], + notificationType: json["notificationType"] == null ? null : json["notificationType"], + referenceItemId: json["referenceItemId"] == null ? null : json["referenceItemId"], + notificationTitle: json["notificationTitle"] == null ? null : json["notificationTitle"], + enableAt: json["enableAt"] == null ? null : json["enableAt"], + applicationItemId: json["applicationItemId"], + startDate: json["startDate"], + endDate: json["endDate"], + deadline: json["deadline"] == null ? null : json["deadline"], + isRepeat: json["isRepeat"] == null ? null : json["isRepeat"], + channelId: json["channelId"] == null ? null : json["channelId"], + serviceId: json["serviceId"] == null ? null : json["serviceId"], + channelName: json["channelName"] == null ? null : json["channelName"], + serviceName: json["serviceName"] == null ? null : json["serviceName"], + isDeleted: json["isDeleted"] == null ? null : json["isDeleted"], + showDelete: json["showDelete"] == null ? null : json["showDelete"], + advertisement: json["advertisement"] == null ? null : Advertisement.fromJson(json["advertisement"]), + survey: json["survey"] == null ? null : SurveyModel.fromJson(json["survey"]), + isActive: json["isActive"], + pageSize: json["pageSize"], + pageNo: json["pageNo"], + languageId: json["languageId"], + ); Map toJson() => { - "notificationMasterId": notificationMasterId == null ? null : notificationMasterId, - "notificationType": notificationType == null ? null : notificationType, - "referenceItemId": referenceItemId == null ? null : referenceItemId, - "notificationTitle": notificationTitle == null ? null : notificationTitle, - "enableAt": enableAt == null ? null : enableAt, - "applicationItemId": applicationItemId, - "startDate": startDate, - "endDate": endDate, - "isRepeat": isRepeat == null ? null : isRepeat, - "channelId": channelId == null ? null : channelId, - "serviceId": serviceId == null ? null : serviceId, - "channelName": channelName == null ? null : channelName, - "serviceName": serviceName == null ? null : serviceName, - "isDeleted": isDeleted == null ? null : isDeleted, - "showDelete": showDelete == null ? null : showDelete, - "advertisement": advertisement, - "survey": survey, - "isActive": isActive, - "pageSize": pageSize, - "pageNo": pageNo, - "languageId": languageId, - }; + "notificationMasterId": notificationMasterId == null ? null : notificationMasterId, + "notificationType": notificationType == null ? null : notificationType, + "referenceItemId": referenceItemId == null ? null : referenceItemId, + "notificationTitle": notificationTitle == null ? null : notificationTitle, + "enableAt": enableAt == null ? null : enableAt, + "applicationItemId": applicationItemId, + "startDate": startDate, + "endDate": endDate, + "deadline": deadline == null ? null : deadline , + "isRepeat": isRepeat == null ? null : isRepeat, + "channelId": channelId == null ? null : channelId, + "serviceId": serviceId == null ? null : serviceId, + "channelName": channelName == null ? null : channelName, + "serviceName": serviceName == null ? null : serviceName, + "isDeleted": isDeleted == null ? null : isDeleted, + "showDelete": showDelete == null ? null : showDelete, + "advertisement": advertisement, + "survey": survey, + "isActive": isActive, + "pageSize": pageSize, + "pageNo": pageNo, + "languageId": languageId, + }; } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 965fe52..96ff0a9 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -458,6 +458,11 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return res; } + Future getENSATItgToken() async { + String? res = await DashboardApiClient().getENSATItgToken(); + return res; + } + //Courses API's & Methods Future fetchCourses(BuildContext context) async { try { diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 43552ca..2f4147d 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -185,13 +185,18 @@ class _DashboardScreenState extends State with WidgetsBindingOb ItgMainRes? response = await DashboardApiClient().getAdvertisementDetail(list[ermIndex].notificationMasterId ?? ""); // Utils.hideLoading(context); if (response!.mohemmItgResponseItem!.result!.data != null) { + for (ItgResponseData payload in response.mohemmItgResponseItem!.result!.data!) { + if (payload.notificationMasterId == list[ermIndex].notificationMasterId) { + payload.deadline = list[ermIndex].deadline; + } + } if (list[ermIndex].notificationType == "Survey") { await Navigator.pushNamed(context, AppRoutes.survey, arguments: response.mohemmItgResponseItem!.result!.data!.first); } else { await Navigator.pushNamed( context, AppRoutes.advertisement, - arguments: {"masterId": list[ermIndex].notificationMasterId, "advertisement": response.mohemmItgResponseItem!.result!.data!.first.advertisement}, + arguments: {"masterId": list[ermIndex].notificationMasterId, "advertisement": response.mohemmItgResponseItem!.result!.data!.first}, ); } } @@ -285,7 +290,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb }); }, ), - Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28).expanded, + Image + .asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28) + .expanded, SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async { await Navigator.pushNamed(context, AppRoutes.announcements); }), @@ -317,103 +324,103 @@ class _DashboardScreenState extends State with WidgetsBindingOb child: Consumer( builder: (BuildContext context, DashboardProviderModel model, Widget? child) { return (model.isAttendanceTrackingLoading - ? GetAttendanceTrackingShimmer() - : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: const LinearGradient( - transform: GradientRotation(.46), - begin: Alignment.topRight, - end: Alignment.bottomLeft, - colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], - ), - ), - child: Stack( - alignment: Alignment.center, - children: [ - if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), - if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), - if (model.isTimeRemainingInSeconds != 0) - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 9.height, - Directionality( - textDirection: ui.TextDirection.ltr, - child: CountdownTimer( - endTime: model.endTime, - onEnd: null, - endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), - textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), - ), - ), - LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), - 9.height, - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(20)), - child: LinearProgressIndicator( - value: model.progress, - minHeight: 8, - valueColor: const AlwaysStoppedAnimation(Colors.white), - backgroundColor: const Color(0xff196D73), - ), - ), - ], - ), - ], - ).paddingOnly(top: 12, right: 15, left: 12), - ), - Row( + ? GetAttendanceTrackingShimmer() + : Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + gradient: const LinearGradient( + transform: GradientRotation(.46), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], + ), + ), + child: Stack( + alignment: Alignment.center, + children: [ + if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), + if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), + if (model.isTimeRemainingInSeconds != 0) + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.checkIn.tr().toText12(color: Colors.white), - (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( - color: Colors.white, - isBold: true, - ), - 4.height, - ], - ).paddingOnly(left: 12, right: 12), + 9.height, + Directionality( + textDirection: ui.TextDirection.ltr, + child: CountdownTimer( + endTime: model.endTime, + onEnd: null, + endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ), ), - Container( - margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), - width: 45, - height: 45, - padding: const EdgeInsets.only(left: 10, right: 10), - decoration: BoxDecoration( - color: const Color(0xff259EA4), - borderRadius: BorderRadius.only( - bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), - bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), - ), + LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), + 9.height, + ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(20)), + child: LinearProgressIndicator( + value: model.progress, + minHeight: 8, + valueColor: const AlwaysStoppedAnimation(Colors.white), + backgroundColor: const Color(0xff196D73), ), - child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), - ).onPress(() { - showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); - }), + ), ], ), - ], + ], + ).paddingOnly(top: 12, right: 15, left: 12), + ), + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.checkIn.tr().toText12(color: Colors.white), + (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( + color: Colors.white, + isBold: true, + ), + 4.height, + ], + ).paddingOnly(left: 12, right: 12), ), + Container( + margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), + width: 45, + height: 45, + padding: const EdgeInsets.only(left: 10, right: 10), + decoration: BoxDecoration( + color: const Color(0xff259EA4), + borderRadius: BorderRadius.only( + bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), + bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), + ), + ), + child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), + ).onPress(() { + showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); + }), ], ), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.todayAttendance); - })) + ], + ), + ], + ), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.todayAttendance); + })) .animatedSwither(); }, ), @@ -483,70 +490,70 @@ class _DashboardScreenState extends State with WidgetsBindingOb flex: 2, child: RichText( text: - AppState().isArabic(context) - ? TextSpan( - children: [ - TextSpan( - text: 'اطلع على مميزات', - style: TextStyle( - fontSize: 16, - letterSpacing: -0.2, - fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - fontWeight: FontWeight.w700, - height: 24 / 16, - color: const Color(0xFF5D5E5E), - ), - ), - TextSpan( - text: ' مزايا', - style: TextStyle( - fontSize: 16, - fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - fontWeight: FontWeight.w700, - letterSpacing: -0.2, - height: 24 / 16, - color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - ), - ), - ], - ) - : TextSpan( - children: [ - TextSpan( - text: LocaleKeys.explore.tr() + ' ', - style: const TextStyle( - fontSize: 16, - letterSpacing: -0.2, - fontFamily: 'Poppins', - fontWeight: FontWeight.w700, - height: 24 / 16, - color: Color(0xFF5D5E5E), - ), - ), - TextSpan( - text: LocaleKeys.mazaya.tr(), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w700, - fontFamily: 'Poppins', - letterSpacing: -0.2, - height: 24 / 16, - color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - ), - ), - TextSpan( - text: ' ' + LocaleKeys.benefits.tr(), - style: const TextStyle( - fontSize: 16, - letterSpacing: -0.2, - fontFamily: 'Poppins', - fontWeight: FontWeight.w700, - height: 24 / 16, - color: Color(0xFF5D5E5E), - ), - ), - ], - ), + AppState().isArabic(context) + ? TextSpan( + children: [ + TextSpan( + text: 'اطلع على مميزات', + style: TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: const Color(0xFF5D5E5E), + ), + ), + TextSpan( + text: ' مزايا', + style: TextStyle( + fontSize: 16, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + letterSpacing: -0.2, + height: 24 / 16, + color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + ], + ) + : TextSpan( + children: [ + TextSpan( + text: LocaleKeys.explore.tr() + ' ', + style: const TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: Color(0xFF5D5E5E), + ), + ), + TextSpan( + text: LocaleKeys.mazaya.tr(), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w700, + fontFamily: 'Poppins', + letterSpacing: -0.2, + height: 24 / 16, + color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + TextSpan( + text: ' ' + LocaleKeys.benefits.tr(), + style: const TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: Color(0xFF5D5E5E), + ), + ), + ], + ), ), ), const Expanded(flex: 1, child: SizedBox()), @@ -626,42 +633,42 @@ class _DashboardScreenState extends State with WidgetsBindingOb return model.isOffersLoading ? const OffersShimmerWidget() : InkWell( - onTap: () { - navigateToDetails(data.getOffersList[index]); - }, - child: SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(100)), - border: Border.all(color: MyColors.lightGreyE3Color, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(50)), - child: Hero( - tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, - transitionOnUserGestures: true, - child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain), - ), - ), - ), - 4.height, - Expanded( - child: - AppState().isArabic(context) - ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) - : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + onTap: () { + navigateToDetails(data.getOffersList[index]); + }, + child: SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(100)), + border: Border.all(color: MyColors.lightGreyE3Color, width: 1), + ), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(50)), + child: Hero( + tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, + transitionOnUserGestures: true, + child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain), ), - ], + ), ), - ), - ); + 4.height, + Expanded( + child: + AppState().isArabic(context) + ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) + : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + ), + ], + ), + ), + ); }, separatorBuilder: (BuildContext cxt, int index) => 8.width, itemCount: 9, @@ -684,7 +691,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb mainAxisSize: MainAxisSize.min, children: [ ServicesWidget(), - context.watch().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8), + context + .watch() + .isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8), // context.watch().isTutorialLoading // ? const MarathonBannerShimmer().paddingAll(20) // : Container( @@ -788,28 +797,28 @@ class _DashboardScreenState extends State with WidgetsBindingOb SvgPicture.asset( "assets/icons/chat/chat.svg", color: - !checkIfPrivilegedForChat() - ? MyColors.lightGreyE3Color - : currentIndex == 4 - ? MyColors.grey3AColor - : cProvider.disbaleChatForThisUser - ? MyColors.lightGreyE3Color - : MyColors.grey98Color, + !checkIfPrivilegedForChat() + ? MyColors.lightGreyE3Color + : currentIndex == 4 + ? MyColors.grey3AColor + : cProvider.disbaleChatForThisUser + ? MyColors.lightGreyE3Color + : MyColors.grey98Color, ).paddingAll(4), Consumer( builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { return !checkIfPrivilegedForChat() ? const SizedBox() : Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.chatUConvCounter.toString().toText10(color: Colors.white), - ), - ); + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.chatUConvCounter.toString().toText10(color: Colors.white), + ), + ); }, ), ], @@ -845,9 +854,16 @@ class _DashboardScreenState extends State with WidgetsBindingOb } Widget eventActivityWidget(BuildContext context) { - return (context.watch().isEventLoadingLoading) + return (context + .watch() + .isEventLoadingLoading) ? const MarathonBannerShimmer().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) - : (context.watch().eventActivity != null && context.watch().eventActivity!.isActive == true) + : (context + .watch() + .eventActivity != null && context + .watch() + .eventActivity! + .isActive == true) ? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) : const SizedBox(); } diff --git a/lib/ui/landing/itg/its_add_screen_video_image.dart b/lib/ui/landing/itg/its_add_screen_video_image.dart index 23bfc66..8c4d6ac 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_countdown_timer/index.dart'; +import 'package:jiffy/jiffy.dart'; import 'package:lottie/lottie.dart'; import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; @@ -13,12 +14,14 @@ import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart'; import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads; +import 'package:mohem_flutter_app/models/itg/itg_response_model.dart' as itgres; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/my_video_progress_indicator.dart'; import 'package:provider/provider.dart'; +import 'package:sizer/sizer.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:video_player/video_player.dart'; @@ -42,6 +45,7 @@ class _ITGAdsScreenState extends State { // late File imageFile; late String imageUrl; + itgres.ItgResponseData? advertisementPayload; ads.Advertisement? advertisementData; dynamic data; String? masterID; @@ -52,6 +56,7 @@ class _ITGAdsScreenState extends State { final ValueNotifier hasTimerEnded = ValueNotifier(false); late CountdownTimerController timerController; + CountdownTimerController? deadlineTimerController; void checkFileType() { if (advertisementData!.viewAttachFileColl!.first.contentType!.toLowerCase() == "text") { @@ -128,34 +133,227 @@ class _ITGAdsScreenState extends State { }); } + String getDeadlineText() { + if (advertisementPayload?.deadline == null) { + return ""; + } + + try { + // Parse the deadline string using Jiffy (format: MM/dd/yyyy hh:mm:ss aa) + Jiffy deadlineJiffy = Jiffy.parse(advertisementPayload!.deadline!, pattern: "MM/dd/yyyy hh:mm:ss aa"); + Jiffy nowJiffy = Jiffy.now(); + + // Calculate days left + int daysLeft = deadlineJiffy.diff(nowJiffy, unit: Unit.day).toInt(); + + if (daysLeft < 0) { + // Deadline has passed + int daysAgo = daysLeft.abs(); + if (AppState().isArabic(context)) { + return "انتهى الموعد النهائي منذ $daysAgo ${daysAgo == 1 ? 'يوم' : 'أيام'}"; + } else { + return "Deadline passed $daysAgo ${daysAgo == 1 ? 'day' : 'days'} ago"; + } + } else if (daysLeft == 0) { + // Deadline is today + if (AppState().isArabic(context)) { + return "الموعد النهائي اليوم!"; + } else { + return "Deadline is today!"; + } + } else if (daysLeft == 1) { + // Deadline is tomorrow + if (AppState().isArabic(context)) { + return "الموعد النهائي غداً"; + } else { + return "Deadline is tomorrow"; + } + } else { + // Deadline is in the future + if (AppState().isArabic(context)) { + return "متبقي $daysLeft ${daysLeft <= 10 ? 'أيام' : 'يوم'}"; + } else { + return "$daysLeft ${daysLeft == 1 ? 'day' : 'days'} left"; + } + } + } catch (e) { + logger.e("Error parsing deadline: $e"); + return "Deadline: ${Utils.formatDate(advertisementPayload!.deadline)}"; + } + } + + void initDeadlineTimer() { + if (advertisementPayload?.deadline == null) return; + + try { + // Parse the deadline string using Jiffy (format: MM/dd/yyyy hh:mm:ss aa) + Jiffy deadlineJiffy = Jiffy.parse(advertisementPayload!.deadline!, pattern: "MM/dd/yyyy hh:mm:ss aa"); + DateTime deadlineDate = deadlineJiffy.dateTime; + + int endTime = deadlineDate.millisecondsSinceEpoch; + int currentTime = DateTime.now().millisecondsSinceEpoch; + + // Only create timer if deadline is in the future + if (endTime > currentTime) { + deadlineTimerController = CountdownTimerController( + endTime: endTime, + onEnd: () { + // Timer ended, could trigger a refresh or notification + logger.d("Deadline timer ended"); + }, + ); + } + } catch (e) { + logger.e("Error initializing deadline timer: $e"); + } + } + @override void dispose() { _controller?.dispose(); + deadlineTimerController?.dispose(); super.dispose(); } + // Helper method to get localized text + String _getLocalizedText(String arabic, String english) { + return AppState().isArabic(context) ? arabic : english; + } + + // Build advertisement content text + Widget _buildAdvertisementContent() { + String content = AppState().isArabic(context) ? advertisementData!.viewAttachFileColl![0].base64String! : advertisementData!.viewAttachFileColl![1].base64String!; + + return content.toText16(color: MyColors.darkTextColor); + } + + // Build deadline section with timer + Widget _buildDeadlineSection() { + if (deadlineTimerController != null) { + return Center( + child: Column(crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [_buildEndDateText(), 4.height, _buildTimeRemainingRow(), 8.height]), + ); + } else { + return Center(child: _buildEndDateText(isLargeText: true)); + } + } + + // Build end date text + Widget _buildEndDateText({bool isLargeText = false}) { + String label = _getLocalizedText("تاريخ الانتهاء: ", "End Date: "); + String fullText = label + advertisementPayload!.deadline!; + + return isLargeText ? fullText.toText16(color: MyColors.darkTextColor) : fullText.toText14(color: MyColors.darkTextColor); + } + + // Build time remaining row with timer + Widget _buildTimeRemainingRow() { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [_getLocalizedText("الوقت المتبقي", "Time Remaining").toText16(color: MyColors.darkTextColor, isBold: true), 8.width, _buildCountdownTimer()], + ); + } + + // Build countdown timer widget + Widget _buildCountdownTimer() { + return CountdownTimer( + controller: deadlineTimerController, + endWidget: _getLocalizedText("انتهى الموعد النهائي!", "Deadline Expired!").toText16(color: MyColors.redColor, isBold: true), + textStyle: const TextStyle(color: MyColors.darkTextColor, fontSize: 16, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ); + } + + // Build action buttons list + Widget _buildActionButtons() { + return ListView.separated( + itemCount: advertisementData!.actionButtonsColl?.length ?? 0, + separatorBuilder: (cxt, index) => 16.height, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) { + var actionButton = advertisementData!.actionButtonsColl![index]; + String btnText = _getLocalizedText(actionButton.btnTextAr, actionButton.btnTextEn); + + return DefaultButton(btnText, () => _handleButtonAction(actionButton)); + }, + ); + } + + // Handle button action based on type + Future _handleButtonAction(actionButton) async { + String actionValue = actionButton.actionValue.toLowerCase(); + + if (actionValue == "skip") { + Navigator.pop(context); + return; + } + + String actionType = actionButton.actionType?.toLowerCase() ?? ''; + + if (actionType == 'redirect' && actionValue == 'external') { + await _handleExternalRedirect(actionButton.url); + } else if (actionType == 'redirect' && actionValue == 'internal') { + await _handleInternalRedirect(actionButton.url); + } else if (actionType == 'eit' && actionValue == 'internal') { + await _handleEitInternal(actionButton.url); + } else { + await _handleExternalRedirect(actionButton.iconOrImage); + } + } + + // Handle external URL redirect + Future _handleExternalRedirect(String url) async { + Uri uri = Uri.parse(url); + await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) { + Utils.showToast('Could not launch'); + }); + Navigator.pop(context); + } + + // Handle internal route navigation + Future _handleInternalRedirect(String url) async { + await Navigator.pushNamed(context, url); + } + + // Handle EIT internal navigation + Future _handleEitInternal(String url) async { + var pro = Provider.of(context, listen: false); + List menuList = + pro.getMenuEntriesList?.where((element) => element.parentMenuName == url && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? []; + + Navigator.pushNamed(context, AppRoutes.servicesMenuListScreen, arguments: ServicesMenuListScreenParams(advertisementData!.advertisementTitle!, menuList)); + } + @override Widget build(BuildContext context) { data = ModalRoute.of(context)!.settings.arguments; - advertisementData ??= data["advertisement"] as ads.Advertisement; + advertisementPayload ??= data["advertisement"] as itgres.ItgResponseData; + advertisementData = advertisementPayload!.advertisement; masterID ??= data["masterId"]; if (advertisementData != null) { checkFileType(); - videoDuration = advertisementData?.durationInSeconds ?? 0; - timerController = CountdownTimerController(endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, onEnd: onTimerEnd); + if (isTextURL) { + if (deadlineTimerController == null) { + initDeadlineTimer(); + } + } else { + videoDuration = advertisementData?.durationInSeconds ?? 0; + timerController = CountdownTimerController(endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, onEnd: onTimerEnd); + } } return Scaffold( backgroundColor: isTextURL ? Colors.white : Colors.black, - appBar: isTextURL - ? AppBar( - centerTitle: true, - automaticallyImplyLeading: false, - backgroundColor: Colors.white, - title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitle!).toText24(color: MyColors.darkTextColor, isBold: true), - - //advertisementData!.viewAttachFileColl!.first.base64String!.toText24(color: MyColors.darkTextColor, isBold: true), - ) - : null, + appBar: + isTextURL + ? AppBar( + centerTitle: true, + automaticallyImplyLeading: false, + backgroundColor: Colors.white, + title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitle!).toText24(color: MyColors.darkTextColor, isBold: true), + ) + : null, body: Stack( children: [ if (isVideo) @@ -168,38 +366,33 @@ class _ITGAdsScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Center( - child: isAudio - ? Lottie.asset(MyLottieConsts.audioPlaybackLottie) - : AspectRatio( - aspectRatio: _controller!.value.aspectRatio, - child: Stack( - alignment: Alignment.bottomCenter, - children: [ - VideoPlayer(_controller!), - if (advertisementData?.isOptional ?? false) - Positioned( - top: 4, - right: 8, - child: Container( - padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4), - decoration: BoxDecoration(color: Colors.white.withOpacity(0.5), borderRadius: BorderRadius.circular(30)), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text(AppState().isArabic(context) ? "يتخطى" : "Skip"), - Icon(Icons.skip_next), - ], - ), - ).onPress(() { - Navigator.pop(context); - DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Skip").then((value) { - logger.d(value); - }); - }), - ), - ], + child: + isAudio + ? Lottie.asset(MyLottieConsts.audioPlaybackLottie) + : AspectRatio( + aspectRatio: _controller!.value.aspectRatio, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + VideoPlayer(_controller!), + if (advertisementData?.isOptional ?? false) + Positioned( + top: 4, + right: 8, + child: Container( + padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4), + decoration: BoxDecoration(color: Colors.white.withOpacity(0.5), borderRadius: BorderRadius.circular(30)), + child: Row(mainAxisSize: MainAxisSize.min, children: [Text(AppState().isArabic(context) ? "يتخطى" : "Skip"), Icon(Icons.skip_next)]), + ).onPress(() { + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Skip").then((value) { + logger.d(value); + }); + }), + ), + ], + ), ), - ), ), 30.height, CountdownTimer( @@ -243,13 +436,13 @@ class _ITGAdsScreenState extends State { btnText!, hasTimerEndedBool ? () async { - Navigator.pop(context); - DashboardApiClient() - .setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue) - .then((value) { - logger.d(value); - }); - } + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then(( + value, + ) { + logger.d(value); + }); + } : null, disabledColor: Colors.transparent, textColor: !hasTimerEndedBool ? Colors.white.withOpacity(.5) : Colors.white, @@ -257,15 +450,12 @@ class _ITGAdsScreenState extends State { ], ); } - return DefaultButton( - btnText!, - () async { - Navigator.pop(context); - DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((value) { - logger.d(value); - }); - }, - ).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8); + return DefaultButton(btnText!, () async { + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((value) { + logger.d(value); + }); + }).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8); }, // gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( // crossAxisCount: 1, @@ -338,9 +528,7 @@ class _ITGAdsScreenState extends State { ], ); } else { - return const Center( - child: CircularProgressIndicator(), - ); + return const Center(child: CircularProgressIndicator()); } }, ), @@ -353,19 +541,17 @@ class _ITGAdsScreenState extends State { children: [ Image.network(imageUrl), 50.height, - Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress( - () { - try { - Navigator.pop(context); - DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Like").then((value) { - logger.d(value); - }); - } catch (ex) { - logger.wtf(ex); - Utils.handleException(ex, context, null); - } - }, - ), + Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress(() { + try { + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Like").then((value) { + logger.d(value); + }); + } catch (ex) { + logger.wtf(ex); + Utils.handleException(ex, context, null); + } + }), ], ), ), @@ -375,60 +561,7 @@ class _ITGAdsScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, - children: [ - (AppState().isArabic(context) ? advertisementData!.viewAttachFileColl![0].base64String! : advertisementData!.viewAttachFileColl![1].base64String!) - .toText16(color: MyColors.darkTextColor), - 24.height, - ListView.separated( - itemCount: advertisementData!.actionButtonsColl?.length ?? 0, - separatorBuilder: (cxt, index) => 16.height, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - padding: EdgeInsets.zero, - itemBuilder: (cxt, index) => DefaultButton( - AppState().isArabic(context) ? advertisementData!.actionButtonsColl![index].btnTextAr : advertisementData!.actionButtonsColl![index].btnTextEn, - () async { - if (advertisementData!.actionButtonsColl![index].actionValue.toLowerCase() == "skip") { - Navigator.pop(context); - } else { - if (advertisementData!.actionButtonsColl![index].actionType!.toLowerCase() == 'redirect' && advertisementData!.actionButtonsColl![index].actionValue!.toLowerCase() == - 'external') { - Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].url!); - await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) { - // print(err); - Utils.showToast('Could not launch'); - }); - Navigator.pop(context); - } else if (advertisementData!.actionButtonsColl![index].actionType!.toLowerCase() == 'redirect' && advertisementData!.actionButtonsColl![index].actionValue!.toLowerCase() == - 'internal') { - - await Navigator.pushNamed(context, advertisementData!.actionButtonsColl![index].url!); - - } else if(advertisementData!.actionButtonsColl![index].actionType!.toLowerCase() == 'eit' && advertisementData!.actionButtonsColl![index].actionValue!.toLowerCase() == - 'internal'){ - var pro = Provider.of(context, listen: false); - List _menuList = - pro.getMenuEntriesList?.where((element) => element.parentMenuName == advertisementData!.actionButtonsColl![index].url && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? []; - Navigator.pushNamed(context, AppRoutes.servicesMenuListScreen, arguments: ServicesMenuListScreenParams(advertisementData!.advertisementTitle!, _menuList)); - - } - else{ - Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].iconOrImage); - // if (await canLaunchUrl(uri)) { - await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) { - // print(err); - Utils.showToast('Could not launch'); - }); - Navigator.pop(context); - // } else { - // Utils.showToast('Could not launch'); - // } - } - } - }, - ), - ), - ], + children: [_buildAdvertisementContent(), 24.height, _buildDeadlineSection(), 24.height, _buildActionButtons()], ), ), ], diff --git a/lib/ui/landing/widget/app_drawer.dart b/lib/ui/landing/widget/app_drawer.dart index 44843be..b9bdbc4 100644 --- a/lib/ui/landing/widget/app_drawer.dart +++ b/lib/ui/landing/widget/app_drawer.dart @@ -49,18 +49,32 @@ class _AppDrawerState extends State { children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 24), const Icon(Icons.clear).onPress(() => Navigator.pop(context))], + children: [ + Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 24), + const Icon(Icons.clear).onPress(() => Navigator.pop(context)), + ], ).paddingOnly(left: 4, right: 14), Row( children: [ AppState().memberInformationList!.eMPLOYEEIMAGE == null - ? SvgPicture.asset("assets/images/user.svg", height: 52, width: 52) - : CircleAvatar(radius: 52 / 2, backgroundImage: MemoryImage(Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE!)), backgroundColor: Colors.black), + ? SvgPicture.asset( + "assets/images/user.svg", + height: 52, + width: 52, + ) + : CircleAvatar( + radius: 52 / 2, + backgroundImage: MemoryImage(Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE!)), + backgroundColor: Colors.black, + ), 12.width, Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [AppState().memberInformationList!.eMPLOYEENAME!.toText18(isBold: true), AppState().memberInformationList!.getPositionName().toText14(weight: FontWeight.w500)], - ).expanded, + children: [ + AppState().memberInformationList!.eMPLOYEENAME!.toText18(isBold: true), + AppState().memberInformationList!.getPositionName().toText14(weight: FontWeight.w500), + ], + ).expanded ], ).paddingOnly(left: 14, right: 14, top: 21, bottom: 21), // Row( @@ -85,77 +99,67 @@ class _AppDrawerState extends State { // ), // ], // ).paddingOnly(left: 14, right: 14, bottom: 14), - const Divider(height: 1, thickness: 1, color: MyColors.lightGreyEFColor), + const Divider( + height: 1, + thickness: 1, + color: MyColors.lightGreyEFColor, + ), ListView( padding: const EdgeInsets.only(top: 21, bottom: 21), children: [ ListView.builder( - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: drawerMenuItemList.length, - itemBuilder: (cxt, index) { - return menuItem( - drawerMenuItemList[index].icon, - drawerMenuItemList[index].title, - drawerMenuItemList[index].routeName, - onPress: () { + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: drawerMenuItemList.length, + itemBuilder: (cxt, index) { + return menuItem(drawerMenuItemList[index].icon, drawerMenuItemList[index].title, drawerMenuItemList[index].routeName, onPress: () { Navigator.pushNamed(context, drawerMenuItemList[index].routeName); - }, - ); - }, - ), + }); + }), menuItem("assets/images/drawer/employee_id.svg", LocaleKeys.employeeDigitalID.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: EmployeeDigitialIdDialog())), if (AppState().businessCardPrivilege) - menuItem( - "assets/images/drawer/view_business_card.svg", - LocaleKeys.viewBusinessCard.tr(), - "", - closeDrawer: false, - onPress: () => showMDialog(context, child: BusinessCardDialog(), isBusniessCard: true), - ), - menuItem( - "assets/images/drawer/logout.svg", - LocaleKeys.logout.tr(), - "", - color: MyColors.redA3Color, - closeDrawer: false, - onPress: () async { - await Utils.performLogout(context, chatData); - }, - ), + menuItem("assets/images/drawer/view_business_card.svg", LocaleKeys.viewBusinessCard.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: BusinessCardDialog(), isBusniessCard: true)), + menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: (){Utils.performLogout(context, chatData);}), // menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: () {Navigator.pushNamed(context, AppRoutes.survey,); ], ).expanded, - const Divider(height: 1, thickness: 1, color: MyColors.lightGreyEFColor), + const Divider( + height: 1, + thickness: 1, + color: MyColors.lightGreyEFColor, + ), Row( children: [ RichText( - text: TextSpan( - text: LocaleKeys.poweredBy.tr() + " ", - style: const TextStyle(color: MyColors.grey98Color, fontSize: 14, letterSpacing: -0.56, fontWeight: FontWeight.w600), - children: [TextSpan(text: LocaleKeys.cloudSolutions.tr(), style: const TextStyle(color: MyColors.grey3AColor, fontSize: 14, letterSpacing: -0.56, fontWeight: FontWeight.w600))], - ), + text: TextSpan(text: LocaleKeys.poweredBy.tr() + " ", style: const TextStyle(color: MyColors.grey98Color, fontSize: 14, letterSpacing: -0.56, fontWeight: FontWeight.w600), children: [ + TextSpan( + text: LocaleKeys.cloudSolutions.tr(), + style: const TextStyle(color: MyColors.grey3AColor, fontSize: 14, letterSpacing: -0.56, fontWeight: FontWeight.w600), + ), + ]), ).expanded, - Image.asset("assets/images/logos/bn_cloud_soloution.jpg", width: 40, height: 40), + Image.asset("assets/images/logos/bn_cloud_soloution.jpg", width: 40, height: 40) ], - ).paddingOnly(left: 21, right: 21, top: 21), + ).paddingOnly(left: 21, right: 21, top: 21) ], ).paddingOnly(top: 21, bottom: 21), ); } Widget menuItem(String icon, String title, String routeName, {Color? color, bool closeDrawer = true, VoidCallback? onPress}) { - return Row(children: [SvgPicture.asset(icon, height: 20, width: 20), 9.width, title.toText14(color: color, textAlign: AppState().isArabic(context) ? TextAlign.right : null).expanded]) - .paddingOnly(left: 21, top: 10, bottom: 10, right: 21) - .onPress( - closeDrawer - ? () async { - Navigator.pop(context); - Future.delayed(const Duration(microseconds: 200), onPress); - } - : onPress!, - ); + return Row( + children: [ + SvgPicture.asset(icon, height: 20, width: 20), + 9.width, + title.toText14(color: color, textAlign: AppState().isArabic(context) ? TextAlign.right : null).expanded, + ], + ).paddingOnly(left: 21, top: 10, bottom: 10, right: 21).onPress(closeDrawer + ? () async { + Navigator.pop(context); + Future.delayed(const Duration(microseconds: 200), onPress); + } + : onPress!); } void postLanguageChange(BuildContext context) { @@ -167,13 +171,13 @@ class _AppDrawerState extends State { setState(() {}); } - void performLogout() async { - AppState().isAuthenticated = false; - AppState().isLogged = false; - AppState().setPostParamsInitConfig(); - chatData.disposeData(); - // SharedPreferences prefs = await SharedPreferences.getInstance(); - // await prefs.clear(); - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route route) => false, arguments: null); - } +// void performLogout() async { +// // AppState().isAuthenticated = false; +// // AppState().isLogged = false; +// // AppState().setPostParamsInitConfig(); +// // chatData.disposeData(); +// // // SharedPreferences prefs = await SharedPreferences.getInstance(); +// // // await prefs.clear(); +// // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route route) => false, arguments: null); +// } } diff --git a/lib/ui/screens/courses/courses_screen.dart b/lib/ui/screens/courses/courses_screen.dart index 598b6cf..3e1ad5c 100644 --- a/lib/ui/screens/courses/courses_screen.dart +++ b/lib/ui/screens/courses/courses_screen.dart @@ -295,7 +295,7 @@ class _CoursesScreenState extends State { void _openCourse(String? url, String? jwtToken) { - Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: url, jwtToken: jwtToken))); + Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: url, jwtToken: jwtToken, ssoType: SsoType.forCourses))); //Utils.showToast(LocaleKeys.courseUrlNotAvailable.tr()); diff --git a/lib/ui/screens/ticket/ticket_detailed_screen.dart b/lib/ui/screens/ticket/ticket_detailed_screen.dart index 7959f39..f59db82 100644 --- a/lib/ui/screens/ticket/ticket_detailed_screen.dart +++ b/lib/ui/screens/ticket/ticket_detailed_screen.dart @@ -58,7 +58,7 @@ class _TicketDetailedScreenState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, - appBar: AppBarWidget(context, title:LocaleKeys.ticketDetails.tr()), + appBar: AppBarWidget(context, title: LocaleKeys.ticketDetails.tr()), body: Column( children: [ ListView( @@ -77,7 +77,7 @@ class _TicketDetailedScreenState extends State { children: [ Row( children: [ - LocaleKeys.currentTicketBalance.tr().toText20().expanded, + LocaleKeys.currentTicketBalance.tr().toText20().expanded, Row( children: [ const Icon(Icons.calendar_month_rounded, color: MyColors.darkIconColor, size: 16), @@ -225,7 +225,7 @@ class _TicketDetailedScreenState extends State { ).expanded, DefaultButton(LocaleKeys.proceedBooking.tr(), () { if (widget.url != null && widget.jwtToken != null) { - Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: widget.url, jwtToken: widget.jwtToken))); + Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: widget.url, jwtToken: widget.jwtToken, ssoType: SsoType.forTicket))); } }).insideContainer, ], diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index d659ea6..63169ac 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:mohem_flutter_app/api/worklist/worklist_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/date_uitl.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; @@ -21,6 +22,7 @@ import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheets/worklist_advance_search_bottom_sheet.dart'; +import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart'; import 'package:provider/provider.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; @@ -107,13 +109,13 @@ class _WorkListScreenState extends State { ), WorkListItemTypeModelData( value: 0, - name: 'COC', + name: 'ENSAT', fullName: LocaleKeys.itemCreation.tr(), active: false, - color: [Color(0xff787299), Color(0xff1AB170)], + color: [const Color(0xff787299), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'COC', - disable: true, + disable: false, ), WorkListItemTypeModelData( value: 0, @@ -135,7 +137,6 @@ class _WorkListScreenState extends State { key: 'HMG_FA_D', disable: false, ), - ]; int? workListItemIndex; @@ -231,6 +232,12 @@ class _WorkListScreenState extends State { if ((itgFormsModel?.requestType?.length ?? 0) > 0) { itgRequestTypeIndex = 0; } + } else if (workListItemTypes[workListItemIndex!].key == "COC") { + + String? enSAToken = await DashboardProviderModel().getENSATItgToken(); + Utils.hideLoading(context); + dynamic url = "${ApiConsts.enSATLiveURL}?empId=${AppState().getUserName}&token=$enSAToken"; + Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: url, jwtToken: enSAToken, ssoType: SsoType.forEnsat))); } else { itgRequestTypeIndex = null; List? _list = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex!].key, pNotificationType.toString()); diff --git a/lib/widgets/sso_webview_widget.dart b/lib/widgets/sso_webview_widget.dart index f584c2c..6db3c32 100644 --- a/lib/widgets/sso_webview_widget.dart +++ b/lib/widgets/sso_webview_widget.dart @@ -1,13 +1,16 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:webview_flutter/webview_flutter.dart'; +// Enum for SSO types +enum SsoType { forTicket, forEnsat, forCourses } + class SsoLoginWebView extends StatefulWidget { final String? url; final String? jwtToken; + final SsoType ssoType; - SsoLoginWebView({this.url, this.jwtToken}); + const SsoLoginWebView({Key? key, required this.url, this.jwtToken, required this.ssoType}) : super(key: key); @override State createState() => _SsoLoginWebViewState(); @@ -16,13 +19,13 @@ class SsoLoginWebView extends StatefulWidget { class _SsoLoginWebViewState extends State { late final WebViewController _controller; String? url; + @override void initState() { - // TODO: implement initState + super.initState(); - url = widget.url ?? "https://Paxes-release.techmaster.in/SSO/HMG"; + url = widget.url ?? ""; - super.initState(); _controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) @@ -30,6 +33,9 @@ class _SsoLoginWebViewState extends State { NavigationDelegate( onProgress: (int progress) { print("WebView is loading (progress: $progress%)"); + if (widget.ssoType == SsoType.forEnsat && progress == 100) { + Utils.hideLoading(context); + } }, onPageStarted: (String url) { print("Page started loading: $url"); @@ -44,22 +50,36 @@ class _SsoLoginWebViewState extends State { print("Web resource error: ${error.description} for URL: ${error.errorType}"); }, ), - ) - ..loadHtmlString(''' + ); + + // Load content based on SSO type + if (widget.ssoType == SsoType.forEnsat) { + // For ENSAT, just load the URL directly (GET request) + _controller.loadRequest(Uri.parse(url!)); + } else { + // For Paxes (Ticket, Courses), use HTML form POST + _controller.loadHtmlString(_buildHtmlContent()); + } + } + + // Build HTML content for the SSO form + String _buildHtmlContent() { + String formAction = url ?? "https://www.paxes.com/sso/hmg"; + + return ''' -
+
-

Redirecting...

+

-'''); +'''; } - ////
@override Widget build(BuildContext context) { - return Scaffold(appBar: null, body:SafeArea(child: WebViewWidget(controller: _controller))); + return Scaffold(appBar: null, body: SafeArea(child: WebViewWidget(controller: _controller))); } } diff --git a/pubspec.yaml b/pubspec.yaml index 7e5a29a..a4eda02 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -112,6 +112,7 @@ dependencies: just_audio: ^0.9.30 # safe_device: ^1.1.2 flutter_layout_grid: ^2.0.1 + jiffy: ^6.4.4 #Huawei Dependencies # huawei_hmsavailability: ^6.6.0+300