Microsoft Clarity implementation contd.

pull/332/head
haroon amjad 3 weeks ago
parent 4eb4d0b37d
commit 1750c7dc44

@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -264,6 +265,11 @@ class ApiClientImp implements ApiClient {
final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr(); final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr();
onFailure(message, -1, failureType: ConnectivityFailure(message)); onFailure(message, -1, failureType: ConnectivityFailure(message));
_analytics.errorTracking.log(endPoint, error: "SocketException: $e"); _analytics.errorTracking.log(endPoint, error: "SocketException: $e");
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_request', _sanitizeRequestBody(requestBody));
Clarity.sendCustomEvent('api_failure');
return; return;
} on http.ClientException catch (e) { } on http.ClientException catch (e) {
final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr(); final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr();
@ -274,6 +280,10 @@ class ApiClientImp implements ApiClient {
final message = LocaleKeys.networkTimeout.tr(); final message = LocaleKeys.networkTimeout.tr();
onFailure(message, -1, failureType: ConnectivityFailure(message)); onFailure(message, -1, failureType: ConnectivityFailure(message));
_analytics.errorTracking.log(endPoint, error: "TimeoutException"); _analytics.errorTracking.log(endPoint, error: "TimeoutException");
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_request', _sanitizeRequestBody(requestBody));
Clarity.sendCustomEvent('api_timeout_failure');
return; return;
} catch (e) { } catch (e) {
final message = LocaleKeys.networkUnknownError.tr(); final message = LocaleKeys.networkUnknownError.tr();
@ -287,6 +297,11 @@ class ApiClientImp implements ApiClient {
if (statusCode < 200 || statusCode >= 400) { if (statusCode < 200 || statusCode >= 400) {
onFailure(LocaleKeys.networkErrorWhileFetching.tr(), statusCode, failureType: StatusCodeFailure(LocaleKeys.networkErrorWhileFetching.tr())); onFailure(LocaleKeys.networkErrorWhileFetching.tr(), statusCode, failureType: StatusCodeFailure(LocaleKeys.networkErrorWhileFetching.tr()));
logApiEndpointError(endPoint, LocaleKeys.networkErrorWhileFetching.tr(), statusCode); logApiEndpointError(endPoint, LocaleKeys.networkErrorWhileFetching.tr(), statusCode);
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_request', _sanitizeRequestBody(requestBody));
Clarity.setCustomTag('api_err_status', statusCode.toString());
Clarity.sendCustomEvent('api_status_code_failure');
} else { } else {
var parsed = json.decode(utf8.decode(response.bodyBytes)); var parsed = json.decode(utf8.decode(response.bodyBytes));
if (isAllowAny) { if (isAllowAny) {
@ -388,6 +403,11 @@ class ApiClientImp implements ApiClient {
); );
logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode); logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode);
} }
Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
Clarity.setCustomTag('api_err_request', _sanitizeRequestBody(requestBody));
Clarity.setCustomTag('api_err_status', statusCode.toString());
Clarity.sendCustomEvent('api_message_status_failure');
} }
} else { } else {
if (parsed['SameClinicApptList'] != null) { if (parsed['SameClinicApptList'] != null) {
@ -666,4 +686,42 @@ class ApiClientImp implements ApiClient {
logApiEndpointError(String endPoint, error, code) { logApiEndpointError(String endPoint, error, code) {
_analytics.errorTracking.log(endPoint, error: error); _analytics.errorTracking.log(endPoint, error: error);
} }
String _getEndofUrl(String url) {
const int clarityLimit = 255;
if (url.length <= clarityLimit) return url;
// Extracts the final 252 characters and prepends '...'
return '...${url.substring(url.length - (clarityLimit - 3))}';
}
String _sanitizeRequestBody(String body) {
if (body.isEmpty) return '';
try {
// Handle standard JSON bodies
final Map<String, dynamic> data = json.decode(body);
// Case-insensitive key matching and removal
data.removeWhere((key, value) => key.toLowerCase() == 'sessionid' || key.toLowerCase() == 'tokenid');
return json.encode(data);
} catch (_) {
// Fallback: Handle Form URL Encoded strings or raw key-value pairs (SessionID=XYZ&TokenID=abc)
String modifiedBody = body;
final sensitiveKeys = ['SessionID', 'TokenID'];
for (var key in sensitiveKeys) {
// Matches "key=value" surrounded by standard query delimiters
final regExp = RegExp(r'' + key + r'=[^&]*&?', caseSensitive: false);
modifiedBody = modifiedBody.replaceAll(regExp, '');
}
// Clean up any trailing trailing ampersands
if (modifiedBody.endsWith('&')) {
modifiedBody = modifiedBody.substring(0, modifiedBody.length - 1);
}
return modifiedBody;
}
}
} }

@ -49,8 +49,8 @@ class AppState {
bool isPaytabsEnabled = false; bool isPaytabsEnabled = false;
void setIsPaytabsEnabled(bool value) { void setIsPaytabsEnabled(bool value) {
// isPaytabsEnabled = value; isPaytabsEnabled = value;
isPaytabsEnabled = false; // isPaytabsEnabled = false;
} }
int? _superUserID; int? _superUserID;

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -139,6 +140,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
@override @override
void initState() { void initState() {
Clarity.setCurrentScreenName('OTP Verification Screen');
super.initState(); super.initState();
authVm = context.read<AuthenticationViewModel>(); authVm = context.read<AuthenticationViewModel>();
focusNode = widget.focusNode ?? FocusNode(); focusNode = widget.focusNode ?? FocusNode();

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_paytabs_bridge/BaseBillingShippingInfo.dart'; import 'package:flutter_paytabs_bridge/BaseBillingShippingInfo.dart';
import 'package:flutter_paytabs_bridge/IOSThemeConfiguration.dart'; import 'package:flutter_paytabs_bridge/IOSThemeConfiguration.dart';
import 'package:flutter_paytabs_bridge/PaymentSDKNetworks.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkConfigurationDetails.dart'; import 'package:flutter_paytabs_bridge/PaymentSdkConfigurationDetails.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkLocale.dart'; import 'package:flutter_paytabs_bridge/PaymentSdkLocale.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkTokenFormat.dart'; import 'package:flutter_paytabs_bridge/PaymentSdkTokenFormat.dart';

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart';
@ -85,6 +86,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
@override @override
void initState() { void initState() {
Clarity.setCurrentScreenName('Appointment Details Page');
super.initState(); super.initState();
scheduleMicrotask(() async { scheduleMicrotask(() async {
@ -892,39 +894,36 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
showCommonBottomSheetWithoutHeight( showCommonBottomSheetWithoutHeight(
title: LocaleKeys.parkingQR.tr(context: context), title: LocaleKeys.parkingQR.tr(context: context),
context, context,
child: SizedBox( child: Column(
// height: 150.h, children: [
child: Column( LocaleKeys.parkingQRDesc.tr(context: context).toText16(),
children: [ SizedBox(height: 16.h),
LocaleKeys.parkingQRDesc.tr(context: context).toText16(), Image.memory(
SizedBox(height: 16.h), myAppointmentsViewModel.parkingQRImageBytes!,
Image.memory( width: 156.w,
myAppointmentsViewModel.parkingQRImageBytes!, height: 156.h,
width: 156.w, fit: BoxFit.cover,
height: 156.h, gaplessPlayback: true, // Prevents blink during image rebuild
fit: BoxFit.cover, ),
gaplessPlayback: true, // Prevents blink during image rebuild SizedBox(height: 16.h),
), CustomButton(
SizedBox(height: 16.h), text: LocaleKeys.done.tr(context: context),
CustomButton( onPressed: () {
text: LocaleKeys.done.tr(context: context), openDoctorScheduleCalendar();
onPressed: () { },
openDoctorScheduleCalendar(); backgroundColor: AppColors.primaryRedColor,
}, borderColor: AppColors.primaryRedColor,
backgroundColor: AppColors.primaryRedColor, textColor: Colors.white,
borderColor: AppColors.primaryRedColor, fontSize: 16.f,
textColor: Colors.white, fontWeight: FontWeight.w600,
fontSize: 16.f, borderRadius: 12.r,
fontWeight: FontWeight.w600, padding: EdgeInsets.symmetric(horizontal: 10.w),
borderRadius: 12.r, height: 50.h,
padding: EdgeInsets.symmetric(horizontal: 10.w), icon: AppAssets.checkmark_icon,
height: 50.h, iconColor: Colors.white,
icon: AppAssets.checkmark_icon, iconSize: 18.h,
iconColor: Colors.white, ).paddingSymmetrical(0.h, 0.h),
iconSize: 18.h, ],
).paddingSymmetrical(0.h, 0.h),
],
),
), ),
callBackFunc: () {}, callBackFunc: () {},
isFullScreen: false, isFullScreen: false,
@ -1312,6 +1311,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
case 50: case 50:
// return LocaleKeys.confirmLiveCare.tr(context: context); // return LocaleKeys.confirmLiveCare.tr(context: context);
case 90: case 90:
Clarity.setCurrentScreenName('Appointment CheckIn Page');
showCommonBottomSheetWithoutHeight(context, showCommonBottomSheetWithoutHeight(context,
title: LocaleKeys.onlineCheckIn.tr(context: context), title: LocaleKeys.onlineCheckIn.tr(context: context),
child: isAppointmentWithin4Hours child: isAppointmentWithin4Hours
@ -1321,9 +1321,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
) )
: Utils.getOnlineCheckInWidget( : Utils.getOnlineCheckInWidget(
loadingText: LocaleKeys.onlineCheckIn24HoursOnly.tr(context: context), loadingText: LocaleKeys.onlineCheckIn24HoursOnly.tr(context: context),
), ), callBackFunc: () {
callBackFunc: () {}, Clarity.setCurrentScreenName('Appointment Details Page');
isFullScreen: false); }, isFullScreen: false);
default: default:
// return "No Action".needTranslation; // return "No Action".needTranslation;
} }

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:developer'; import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -59,6 +60,7 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
@override @override
void initState() { void initState() {
scheduleMicrotask(() { scheduleMicrotask(() {
Clarity.setCurrentScreenName('Appointment Payment Page');
payfortViewModel.initPayfortViewModel(); payfortViewModel.initPayfortViewModel();
payfortViewModel.setIsApplePayConfigurationLoading(false); payfortViewModel.setIsApplePayConfigurationLoading(false);
myAppointmentsViewModel.getPatientShareAppointment( myAppointmentsViewModel.getPatientShareAppointment(
@ -443,21 +445,24 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true), LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol((myAppointmentsVM.patientAppointmentShareResponseModel!.patientShare ?? 0).toString().toText16(isBold: true), AppColors.blackColor, ClarityUnmask(
13, child: Utils.getPaymentAmountWithSymbol(
isSaudiCurrency: true), (myAppointmentsVM.patientAppointmentShareResponseModel!.patientShare ?? 0).toString().toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: true),
),
], ],
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"VAT 15%".toText14(isBold: true, color: AppColors.greyTextColor), "VAT 15%".toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol( ClarityUnmask(
(myAppointmentsVM.patientAppointmentShareResponseModel!.patientTaxAmount ?? 0).toString() child: Utils.getPaymentAmountWithSymbol(
.toText14(isBold: true, color: AppColors.greyTextColor), (myAppointmentsVM.patientAppointmentShareResponseModel!.patientTaxAmount ?? 0).toString().toText14(isBold: true, color: AppColors.greyTextColor),
AppColors.greyTextColor, AppColors.greyTextColor,
13, 13,
isSaudiCurrency: true), isSaudiCurrency: true),
),
], ],
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h), SizedBox(height: 17.h),
@ -465,10 +470,11 @@ class _AppointmentPaymentPageState extends State<AppointmentPaymentPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
"".toText14(isBold: true), "".toText14(isBold: true),
Utils.getPaymentAmountWithSymbol( ClarityUnmask(
(myAppointmentsVM.patientAppointmentShareResponseModel!.patientShareWithTax ?? 0).toString().toText24(isBold: true), AppColors.blackColor, child: Utils.getPaymentAmountWithSymbol(
17, (myAppointmentsVM.patientAppointmentShareResponseModel!.patientShareWithTax ?? 0).toString().toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: true), isSaudiCurrency: true),
),
], ],
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
Platform.isIOS Platform.isIOS

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -309,16 +310,18 @@ class _AppointmentCardState extends State<AppointmentCard> {
? '${(widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital").substring(0, 15)}...' ? '${(widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital").substring(0, 15)}...'
: widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital") : widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital")
.toShimmer2(isShow: widget.isLoading), .toShimmer2(isShow: widget.isLoading),
Directionality( ClarityUnmask(
textDirection: ui.TextDirection.ltr, child: Directionality(
child: AppCustomChipWidget( textDirection: ui.TextDirection.ltr,
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), child: AppCustomChipWidget(
icon: AppAssets.appointment_calendar_icon, labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
richText: widget.isLoading icon: AppAssets.appointment_calendar_icon,
? 'Cardiology'.toText10().toShimmer2(isShow: widget.isLoading) richText: widget.isLoading
: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)}" ? 'Cardiology'.toText10().toShimmer2(isShow: widget.isLoading)
.toText10(isEnglishOnly: true, isBold: true), : "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)}"
).toShimmer2(isShow: widget.isLoading), .toText10(isEnglishOnly: true, isBold: true),
).toShimmer2(isShow: widget.isLoading),
),
), ),
// AppCustomChipWidget( // AppCustomChipWidget(

@ -1,5 +1,6 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -134,17 +135,18 @@ class AppointmentDoctorCard extends StatelessWidget {
labelText: patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital", labelText: patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w), labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
), ),
Directionality( ClarityUnmask(
textDirection: ui.TextDirection.ltr, child: Directionality(
child: AppCustomChipWidget( textDirection: ui.TextDirection.ltr,
labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), child: AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon, labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w),
richText: icon: AppAssets.doctor_calendar_icon,
"${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang( richText: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(
DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate),
false, false,
)}" )}"
.toText10(isBold: true), .toText10(isBold: true),
),
), ),
), ),
AppCustomChipWidget( AppCustomChipWidget(

@ -1,3 +1,4 @@
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -32,6 +33,7 @@ class LoginScreenState extends State<LoginScreen> {
@override @override
void initState() { void initState() {
Clarity.setCurrentScreenName('Login Screen');
super.initState(); super.initState();
_nationalIdFocusNode = FocusNode(); _nationalIdFocusNode = FocusNode();

@ -1,5 +1,6 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -37,6 +38,7 @@ class _SavedLogin extends State<SavedLogin> {
@override @override
void initState() { void initState() {
Clarity.setCurrentScreenName('Last Login Screen');
authVm = context.read<AuthenticationViewModel>(); authVm = context.read<AuthenticationViewModel>();
appState = getIt.get<AppState>(); appState = getIt.get<AppState>();
loginType = LoginTypeExtension.fromValue(appState.getSelectDeviceByImeiRespModelElement!.logInType!)!; loginType = LoginTypeExtension.fromValue(appState.getSelectDeviceByImeiRespModelElement!.logInType!)!;
@ -58,7 +60,6 @@ class _SavedLogin extends State<SavedLogin> {
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
authVm.loginWithFingerPrintFace(() {}); authVm.loginWithFingerPrintFace(() {});
} }
super.initState(); super.initState();
} }

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
@ -57,6 +58,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
@override @override
void initState() { void initState() {
Clarity.setCurrentScreenName('Book Appointment Page');
authVM = context.read<AuthenticationViewModel>(); authVM = context.read<AuthenticationViewModel>();
scheduleMicrotask(() { scheduleMicrotask(() {
// bookAppointmentsViewModel.selectedTabIndex = 0; // bookAppointmentsViewModel.selectedTabIndex = 0;

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
@ -48,6 +49,12 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
Uint8List? _cachedImageBytes; Uint8List? _cachedImageBytes;
String? _cachedImageDataHash; String? _cachedImageDataHash;
@override
void initState() {
Clarity.setCurrentScreenName('Appointment Review Page');
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false); bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);

@ -1,3 +1,4 @@
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
@ -39,6 +40,7 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
@override @override
void initState() { void initState() {
Clarity.setCurrentScreenName('Search By Doctor Name Page');
_scrollController = ScrollController(); _scrollController = ScrollController();
super.initState(); super.initState();
} }

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
@ -59,6 +60,7 @@ class _SelectClinicPageState extends State<SelectClinicPage> {
@override @override
void initState() { void initState() {
Clarity.setCurrentScreenName('Select Clinic Page');
scheduleMicrotask(() { scheduleMicrotask(() {
bookAppointmentsViewModel.getClinics(); bookAppointmentsViewModel.getClinics();
}); });

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
@ -44,6 +45,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
@override @override
void initState() { void initState() {
Clarity.setCurrentScreenName('Select Doctor Page');
_scrollController = ScrollController(); _scrollController = ScrollController();
scheduleMicrotask(() { scheduleMicrotask(() {
bookAppointmentsViewModel.setIsNearestAppointmentSelected(true); bookAppointmentsViewModel.setIsNearestAppointmentSelected(true);

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -59,6 +60,7 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
@override @override
void initState() { void initState() {
Clarity.setCurrentScreenName('Select Doctor Free Slot Page');
_calendarController = CalendarController(); _calendarController = CalendarController();
scheduleMicrotask(() { scheduleMicrotask(() {
_events = { _events = {
@ -98,54 +100,56 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
child: Localizations.override( child: Localizations.override(
context: context, context: context,
locale: isArabic ? const Locale('ar', 'SA') : const Locale('en'), locale: isArabic ? const Locale('ar', 'SA') : const Locale('en'),
child: SfCalendar( child: ClarityUnmask(
controller: _calendarController, child: SfCalendar(
minDate: DateTime.now(), controller: _calendarController,
showNavigationArrow: true, minDate: DateTime.now(),
// headerHeight: 60.h, showNavigationArrow: true,
headerStyle: CalendarHeaderStyle( // headerHeight: 60.h,
backgroundColor: AppColors.transparent, headerStyle: CalendarHeaderStyle(
textAlign: isArabic ? TextAlign.end : TextAlign.start, backgroundColor: AppColors.transparent,
textStyle: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.primaryRedColor), textAlign: isArabic ? TextAlign.end : TextAlign.start,
), textStyle: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.primaryRedColor),
viewHeaderStyle: ViewHeaderStyle(
// backgroundColor: AppColors.scaffoldBgColor,
dayTextStyle: TextStyle(fontSize: 14.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.textColor),
),
view: CalendarView.month,
todayHighlightColor: Colors.transparent,
todayTextStyle: TextStyle(color: AppColors.textColor, fontWeight: FontWeight.bold),
selectionDecoration: ShapeDecoration(
color: AppColors.transparent,
shape: SmoothRectangleBorder(
borderRadius: BorderRadius.circular(10.r),
smoothness: 1,
side: BorderSide(color: AppColors.primaryRedColor, width: 1.5),
), ),
), viewHeaderStyle: ViewHeaderStyle(
cellBorderColor: AppColors.transparent, // backgroundColor: AppColors.scaffoldBgColor,
dataSource: MeetingDataSource(_getDataSource()), dayTextStyle: TextStyle(fontSize: 14.f, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.textColor),
monthCellBuilder: (context, details) => Padding( ),
padding: EdgeInsets.all(12.h), view: CalendarView.month,
child: details.date.day.toString().toText14( todayHighlightColor: Colors.transparent,
isCenter: true, todayTextStyle: TextStyle(color: AppColors.textColor, fontWeight: FontWeight.bold),
color: details.date == _calendarController.selectedDate ? AppColors.primaryRedColor : AppColors.textColor, selectionDecoration: ShapeDecoration(
isEnglishOnly: true, color: AppColors.transparent,
), shape: SmoothRectangleBorder(
), borderRadius: BorderRadius.circular(10.r),
monthViewSettings: MonthViewSettings( smoothness: 1,
dayFormat: "EEE", side: BorderSide(color: AppColors.primaryRedColor, width: 1.5),
appointmentDisplayMode: MonthAppointmentDisplayMode.indicator, ),
showTrailingAndLeadingDates: false,
appointmentDisplayCount: 1,
monthCellStyle: MonthCellStyle(
textStyle: TextStyle(fontSize: 19.f),
), ),
cellBorderColor: AppColors.transparent,
dataSource: MeetingDataSource(_getDataSource()),
monthCellBuilder: (context, details) => Padding(
padding: EdgeInsets.all(12.h),
child: details.date.day.toString().toText14(
isCenter: true,
color: details.date == _calendarController.selectedDate ? AppColors.primaryRedColor : AppColors.textColor,
isEnglishOnly: true,
),
),
monthViewSettings: MonthViewSettings(
dayFormat: "EEE",
appointmentDisplayMode: MonthAppointmentDisplayMode.indicator,
showTrailingAndLeadingDates: false,
appointmentDisplayCount: 1,
monthCellStyle: MonthCellStyle(
textStyle: TextStyle(fontSize: 19.f),
),
),
onTap: (CalendarTapDetails details) {
_calendarController.selectedDate = details.date;
_onDaySelected(details.date!);
},
), ),
onTap: (CalendarTapDetails details) {
_calendarController.selectedDate = details.date;
_onDaySelected(details.date!);
},
), ),
), ),
), ),
@ -153,35 +157,37 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
SizedBox(height: 10.h), SizedBox(height: 10.h),
Transform.translate( Transform.translate(
offset: const Offset(0.0, -10.0), offset: const Offset(0.0, -10.0),
child: selectedDateDisplay.toText16(isBold: true, isEnglishOnly: !isArabic), child: ClarityUnmask(child: selectedDateDisplay.toText16(isBold: true, isEnglishOnly: !isArabic)),
), ),
//TODO: Add Next Day Span here //TODO: Add Next Day Span here
dayEvents.isNotEmpty dayEvents.isNotEmpty
? ConstrainedBox( ? ClarityUnmask(
constraints: BoxConstraints( child: ConstrainedBox(
maxHeight: MediaQuery.of(context).size.height * 0.15, constraints: BoxConstraints(
minHeight: 0, maxHeight: MediaQuery.of(context).size.height * 0.15,
), minHeight: 0,
child: Directionality( ),
textDirection: isArabic ? ui.TextDirection.rtl : ui.TextDirection.ltr, child: Directionality(
child: SingleChildScrollView( textDirection: isArabic ? ui.TextDirection.rtl : ui.TextDirection.ltr,
scrollDirection: Axis.vertical, child: SingleChildScrollView(
child: Wrap( scrollDirection: Axis.vertical,
direction: Axis.horizontal, child: Wrap(
alignment: WrapAlignment.start, direction: Axis.horizontal,
spacing: 6.h, alignment: WrapAlignment.start,
runSpacing: 6.h, spacing: 6.h,
children: List.generate( runSpacing: 6.h,
dayEvents.length, children: List.generate(
(index) => TimeSlotChip( dayEvents.length,
label: dayEvents[index].isoTime!, (index) => TimeSlotChip(
isSelected: index == selectedButtonIndex, label: dayEvents[index].isoTime!,
onTap: () { isSelected: index == selectedButtonIndex,
setState(() { onTap: () {
selectedButtonIndex = index; setState(() {
selectedTime = dayEvents[index].isoTime!; selectedButtonIndex = index;
}); selectedTime = dayEvents[index].isoTime!;
}, });
},
),
), ),
), ),
), ),

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:developer'; import 'dart:developer';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
@ -112,6 +113,7 @@ class _LandingPageState extends State<LandingPage> {
@override @override
void initState() { void initState() {
Clarity.setCurrentScreenName('Landing Page');
authVM = context.read<AuthenticationViewModel>(); authVM = context.read<AuthenticationViewModel>();
habibWalletVM = context.read<HabibWalletViewModel>(); habibWalletVM = context.read<HabibWalletViewModel>();
appointmentRatingViewModel = context.read<AppointmentRatingViewModel>(); appointmentRatingViewModel = context.read<AppointmentRatingViewModel>();

@ -60,9 +60,9 @@ class _SplashScreenState extends State<SplashPage> {
ZoomService().initializeZoomSDK(); ZoomService().initializeZoomSDK();
// if (!kDebugMode) { if (!kDebugMode) {
// _initializeClarity(); _initializeClarity();
// } }
if (isAppOpenedFromCall) { if (isAppOpenedFromCall) {
navigateToTeleConsult(); navigateToTeleConsult();
@ -87,7 +87,7 @@ class _SplashScreenState extends State<SplashPage> {
void _initializeClarity() { void _initializeClarity() {
final config = ClarityConfig( final config = ClarityConfig(
projectId: "x0qgorlez4", // You can find it on the Settings page of Clarity dashboard. projectId: "x0qgorlez4", // You can find it on the Settings page of Clarity dashboard.
logLevel: LogLevel.Verbose, // Optional: Set the log level (Verbose, Debug, Info, Warning, Error, None) logLevel: LogLevel.Error, // Optional: Set the log level (Verbose, Debug, Info, Warning, Error, None)
); );
Clarity.initialize(context, config); Clarity.initialize(context, config);

Loading…
Cancel
Save