Merge pull request 'Symptoms Checker Module (faiz_dev)' (#163) from faiz_dev into master

Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/163
pull/165/head
Haroon6138 2 months ago
commit b6c665cbf1

@ -0,0 +1,5 @@
<svg width="24" height="22" viewBox="0 0 24 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="7" cy="7" r="7" fill="#0B85F7" fill-opacity="0.75"/>
<circle cx="17" cy="7" r="7" fill="#18C273" fill-opacity="0.75"/>
<circle cx="12" cy="15" r="7" fill="#ED1C2B" fill-opacity="0.75"/>
</svg>

After

Width:  |  Height:  |  Size: 301 B

@ -841,7 +841,7 @@ class ApiConsts {
static final String getRiskFactors = '$symptomsCheckerApi/GetRiskFactors'; static final String getRiskFactors = '$symptomsCheckerApi/GetRiskFactors';
static final String getSuggestions = '$symptomsCheckerApi/GetSuggestion'; static final String getSuggestions = '$symptomsCheckerApi/GetSuggestion';
static final String diagnosis = '$symptomsCheckerApi/GetDiagnosis'; static final String diagnosis = '$symptomsCheckerApi/GetDiagnosis';
static final String explain = '$symptomsCheckerApi/explain'; static final String explain = '$symptomsCheckerApi/ExplainDiagnosisResult';
//E-REFERRAL SERVICES //E-REFERRAL SERVICES
static final getAllRelationshipTypes = "Services/Patients.svc/REST/GetAllRelationshipTypes"; static final getAllRelationshipTypes = "Services/Patients.svc/REST/GetAllRelationshipTypes";

@ -253,6 +253,7 @@ class AppAssets {
static const String homeBorderedIcon = '$svgBasePath/home_bordered.svg'; static const String homeBorderedIcon = '$svgBasePath/home_bordered.svg';
static const String symptomCheckerIcon = '$svgBasePath/symptom_checker_icon.svg'; static const String symptomCheckerIcon = '$svgBasePath/symptom_checker_icon.svg';
static const String symptomCheckerBottomIcon = '$svgBasePath/symptom_bottom_icon.svg'; static const String symptomCheckerBottomIcon = '$svgBasePath/symptom_bottom_icon.svg';
static const String coloredDotsIcon = '$svgBasePath/colored_dots_icon.svg';
// Water Monitor // Water Monitor
static const String waterBottle = '$svgBasePath/water_bottle.svg'; static const String waterBottle = '$svgBasePath/water_bottle.svg';
@ -352,4 +353,3 @@ class AppAnimations {
static const String ambulanceAlert = '$lottieBasePath/ambulance_alert.json'; static const String ambulanceAlert = '$lottieBasePath/ambulance_alert.json';
static const String rrtAmbulance = '$lottieBasePath/rrt_ambulance.json'; static const String rrtAmbulance = '$lottieBasePath/rrt_ambulance.json';
} }

@ -311,3 +311,150 @@ extension ServiceTypeEnumExt on ServiceTypeEnum {
enum PossibleConditionsSeverityEnum { seekMedicalAdvice, monitorOnly, emergency } enum PossibleConditionsSeverityEnum { seekMedicalAdvice, monitorOnly, emergency }
enum HealthTrackerTypeEnum { bloodSugar, bloodPressure, weightTracker } enum HealthTrackerTypeEnum { bloodSugar, bloodPressure, weightTracker }
// Severity Enum
enum SeverityEnum { mild, moderate, severe }
extension SeverityEnumExtension on SeverityEnum {
int get toInt {
switch (this) {
case SeverityEnum.mild:
return 0;
case SeverityEnum.moderate:
return 1;
case SeverityEnum.severe:
return 2;
}
}
String get displayName {
AppState appState = getIt.get<AppState>();
bool isArabic = appState.getLanguageID() == 1 ? true : false;
switch (this) {
case SeverityEnum.mild:
return isArabic ? 'خفيف' : 'Mild';
case SeverityEnum.moderate:
return isArabic ? 'متوسط' : 'Moderate';
case SeverityEnum.severe:
return isArabic ? 'شديد' : 'Severe';
}
}
static SeverityEnum? fromInt(int value) {
switch (value) {
case 0:
return SeverityEnum.mild;
case 1:
return SeverityEnum.moderate;
case 2:
return SeverityEnum.severe;
default:
return null;
}
}
}
// Triage Level Enum
enum TriageLevelEnum { emergencyAmbulance, emergency, consultation24, consultation, selfCare }
extension TriageLevelEnumExtension on TriageLevelEnum {
int get toInt {
switch (this) {
case TriageLevelEnum.emergencyAmbulance:
return 0;
case TriageLevelEnum.emergency:
return 1;
case TriageLevelEnum.consultation24:
return 2;
case TriageLevelEnum.consultation:
return 3;
case TriageLevelEnum.selfCare:
return 4;
}
}
String get displayName {
AppState appState = getIt.get<AppState>();
bool isArabic = appState.getLanguageID() == 1 ? true : false;
switch (this) {
case TriageLevelEnum.emergencyAmbulance:
return isArabic ? 'طوارئ - إسعاف' : 'Emergency - Ambulance';
case TriageLevelEnum.emergency:
return isArabic ? 'طوارئ' : 'Emergency';
case TriageLevelEnum.consultation24:
return isArabic ? 'استشارة خلال 24 ساعة' : 'Consultation within 24 hours';
case TriageLevelEnum.consultation:
return isArabic ? 'استشارة' : 'Consultation';
case TriageLevelEnum.selfCare:
return isArabic ? 'رعاية ذاتية' : 'Self Care';
}
}
static TriageLevelEnum? fromInt(int value) {
switch (value) {
case 0:
return TriageLevelEnum.emergencyAmbulance;
case 1:
return TriageLevelEnum.emergency;
case 2:
return TriageLevelEnum.consultation24;
case 3:
return TriageLevelEnum.consultation;
case 4:
return TriageLevelEnum.selfCare;
default:
return null;
}
}
}
// Question Type Enum
enum QuestionTypeEnum { single, groupSingle, groupMultiple, duration }
extension QuestionTypeEnumExtension on QuestionTypeEnum {
int get toInt {
switch (this) {
case QuestionTypeEnum.single:
return 0;
case QuestionTypeEnum.groupSingle:
return 1;
case QuestionTypeEnum.groupMultiple:
return 2;
case QuestionTypeEnum.duration:
return 3;
}
}
String get displayName {
AppState appState = getIt.get<AppState>();
bool isArabic = appState.getLanguageID() == 1 ? true : false;
switch (this) {
case QuestionTypeEnum.single:
return isArabic ? 'سؤال واحد' : 'Single';
case QuestionTypeEnum.groupSingle:
return isArabic ? 'مجموعة - اختيار واحد' : 'Group Single';
case QuestionTypeEnum.groupMultiple:
return isArabic ? 'مجموعة - اختيار متعدد' : 'Group Multiple';
case QuestionTypeEnum.duration:
return isArabic ? 'المدة' : 'Duration';
}
}
static QuestionTypeEnum? fromInt(int value) {
switch (value) {
case 0:
return QuestionTypeEnum.single;
case 1:
return QuestionTypeEnum.groupSingle;
case 2:
return QuestionTypeEnum.groupMultiple;
case 3:
return QuestionTypeEnum.duration;
default:
return null;
}
}
}

@ -1,97 +1,97 @@
import 'package:flutter/material.dart'; // import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/enums.dart'; // import 'package:hmg_patient_app_new/core/enums.dart';
//
class ConditionsModel { // class ConditionsModel {
final IconData icon; // final IconData icon;
final String title; // final String title;
final int percentage; // final int percentage;
final String tagText; // final String tagText;
final String clinic; // final String clinic;
final List<String> symptoms; // final List<String> symptoms;
final String description; // final String description;
final String? monitorNote; // final String? monitorNote;
final String? appointmentLabel; // final String? appointmentLabel;
final PossibleConditionsSeverityEnum possibleConditionsSeverityEnum; // final PossibleConditionsSeverityEnum possibleConditionsSeverityEnum;
//
ConditionsModel({ // ConditionsModel({
required this.icon, // required this.icon,
required this.title, // required this.title,
required this.percentage, // required this.percentage,
required this.tagText, // required this.tagText,
required this.clinic, // required this.clinic,
required this.symptoms, // required this.symptoms,
required this.description, // required this.description,
required this.possibleConditionsSeverityEnum, // required this.possibleConditionsSeverityEnum,
this.monitorNote, // this.monitorNote,
this.appointmentLabel, // this.appointmentLabel,
}); // });
} // }
//
List<ConditionsModel> dummyConditions = [ // List<ConditionsModel> dummyConditions = [
ConditionsModel( // ConditionsModel(
icon: Icons.psychology_alt, // icon: Icons.psychology_alt,
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice, // possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice,
title: "Migraine", // title: "Migraine",
percentage: 87, // percentage: 87,
tagText: "Seek Medical Advice", // tagText: "Seek Medical Advice",
clinic: "Internal Medicine Clinic", // clinic: "Internal Medicine Clinic",
symptoms: ["Headache", "Nausea", "Sensitivity to light"], // symptoms: ["Headache", "Nausea", "Sensitivity to light"],
description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.", // description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.",
appointmentLabel: "Book Appointment", // appointmentLabel: "Book Appointment",
), // ),
ConditionsModel( // ConditionsModel(
icon: Icons.deblur, // icon: Icons.deblur,
title: "Tension Headache", // title: "Tension Headache",
percentage: 37, // percentage: 37,
tagText: "Monitor", // tagText: "Monitor",
monitorNote: "No need to visit doctor", // monitorNote: "No need to visit doctor",
clinic: "GP Clinic", // clinic: "GP Clinic",
symptoms: ["Mild head pressure", "Scalp tenderness"], // symptoms: ["Mild head pressure", "Scalp tenderness"],
description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", // description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly, // possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly,
), // ),
ConditionsModel( // ConditionsModel(
icon: Icons.medication_liquid, // icon: Icons.medication_liquid,
title: "Meningitis", // title: "Meningitis",
percentage: 28, // percentage: 28,
tagText: "Emergency", // tagText: "Emergency",
clinic: "Neurology Clinic", // clinic: "Neurology Clinic",
symptoms: ["Mild head pressure", "Scalp tenderness"], // symptoms: ["Mild head pressure", "Scalp tenderness"],
description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", // description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
appointmentLabel: "Book Appointment", // appointmentLabel: "Book Appointment",
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency, // possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency,
), // ),
ConditionsModel( // ConditionsModel(
icon: Icons.psychology_alt, // icon: Icons.psychology_alt,
title: "Migraine", // title: "Migraine",
percentage: 87, // percentage: 87,
tagText: "Seek Medical Advice", // tagText: "Seek Medical Advice",
clinic: "Internal Medicine Clinic", // clinic: "Internal Medicine Clinic",
symptoms: ["Headache", "Nausea", "Sensitivity to light"], // symptoms: ["Headache", "Nausea", "Sensitivity to light"],
description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.", // description: "A migraine is a type of headache that can cause severe throbbing pain, usually on one side of the head.",
appointmentLabel: "Book Appointment", // appointmentLabel: "Book Appointment",
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice, // possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice,
), // ),
ConditionsModel( // ConditionsModel(
icon: Icons.deblur, // icon: Icons.deblur,
title: "Tension Headache", // title: "Tension Headache",
percentage: 37, // percentage: 37,
tagText: "Monitor", // tagText: "Monitor",
monitorNote: "No need to visit doctor", // monitorNote: "No need to visit doctor",
clinic: "GP Clinic", // clinic: "GP Clinic",
symptoms: ["Mild head pressure", "Scalp tenderness"], // symptoms: ["Mild head pressure", "Scalp tenderness"],
description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", // description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly, // possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.monitorOnly,
), // ),
ConditionsModel( // ConditionsModel(
icon: Icons.medication_liquid, // icon: Icons.medication_liquid,
title: "Meningitis", // title: "Meningitis",
percentage: 28, // percentage: 28,
tagText: "Emergency", // tagText: "Emergency",
clinic: "Neurology Clinic", // clinic: "Neurology Clinic",
symptoms: ["Mild head pressure", "Scalp tenderness"], // symptoms: ["Mild head pressure", "Scalp tenderness"],
description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.", // description: "A tension-type headache is generally a mild to moderate pain that feels like a tight band around your head.",
appointmentLabel: "Book Appointment", // appointmentLabel: "Book Appointment",
possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency, // possibleConditionsSeverityEnum: PossibleConditionsSeverityEnum.emergency,
), // ),
]; // ];

@ -1,3 +1,5 @@
import 'package:hmg_patient_app_new/core/enums.dart';
class TriageDataDetails { class TriageDataDetails {
final TriageQuestion? question; final TriageQuestion? question;
final List<TriageCondition>? conditions; final List<TriageCondition>? conditions;
@ -171,7 +173,7 @@ class TriageCondition {
final String? name; final String? name;
final String? commonName; final String? commonName;
final double? probability; final double? probability;
final dynamic conditionDetails; final ConditionDetails? conditionDetails;
TriageCondition({ TriageCondition({
this.id, this.id,
@ -187,7 +189,7 @@ class TriageCondition {
name: json['name'], name: json['name'],
commonName: json['common_name'], commonName: json['common_name'],
probability: json['probability']?.toDouble(), probability: json['probability']?.toDouble(),
conditionDetails: json['condition_details'], conditionDetails: json['condition_details'] != null ? ConditionDetails.fromJson(json['condition_details']) : null,
); );
} }
@ -197,7 +199,7 @@ class TriageCondition {
'name': name, 'name': name,
'common_name': commonName, 'common_name': commonName,
'probability': probability, 'probability': probability,
'condition_details': conditionDetails, 'condition_details': conditionDetails?.toJson(),
}; };
} }
@ -207,3 +209,75 @@ class TriageCondition {
return '${(probability! * 100).toStringAsFixed(1)}%'; return '${(probability! * 100).toStringAsFixed(1)}%';
} }
} }
class ConditionDetails {
final String? icd10Code;
final ConditionCategory? category;
final SeverityEnum? severity;
final TriageLevelEnum? triageLevel;
final String? hint;
final bool? hasPatientEducation;
final String? prevalence;
final String? acuteness;
ConditionDetails({
this.icd10Code,
this.category,
this.severity,
this.triageLevel,
this.hint,
this.hasPatientEducation,
this.prevalence,
this.acuteness,
});
factory ConditionDetails.fromJson(Map<String, dynamic> json) {
return ConditionDetails(
icd10Code: json['icd10_code'],
category: json['category'] != null ? ConditionCategory.fromJson(json['category']) : null,
severity: json['severity'] != null ? SeverityEnumExtension.fromInt(json['severity']) : null,
triageLevel: json['triage_level'] != null ? TriageLevelEnumExtension.fromInt(json['triage_level']) : null,
hint: json['hint'],
hasPatientEducation: json['has_patient_education'],
prevalence: json['prevalence'],
acuteness: json['acuteness'],
);
}
Map<String, dynamic> toJson() {
return {
'icd10_code': icd10Code,
'category': category?.toJson(),
'severity': severity?.toInt,
'triage_level': triageLevel?.toInt,
'hint': hint,
'has_patient_education': hasPatientEducation,
'prevalence': prevalence,
'acuteness': acuteness,
};
}
}
class ConditionCategory {
final String? id;
final String? name;
ConditionCategory({
this.id,
this.name,
});
factory ConditionCategory.fromJson(Map<String, dynamic> json) {
return ConditionCategory(
id: json['id'],
name: json['name'],
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
};
}
}

@ -12,50 +12,42 @@ import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models
import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class SymptomsCheckerRepo { abstract class SymptomsCheckerRepo {
Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>> Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>> getUserDetails({
getUserDetails({
required String userName, required String userName,
required String password, required String password,
}); });
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>> Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>> getBodySymptomsByName({
getBodySymptomsByName({
required List<String> organNames, required List<String> organNames,
required String userSessionToken, required String userSessionToken,
required int gender, required int gender,
}); });
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getRiskFactors({
getRiskFactors({
required int age, required int age,
required String sex, required int gender,
required List<String> evidenceIds, required List<String> evidenceIds,
required String language, required String language,
required String userSessionToken, required String userSessionToken,
required int gender,
required String sessionId, required String sessionId,
}); });
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getSuggestions({
getSuggestions({
required int age, required int age,
required String sex, required int gender,
required List<String> evidenceIds, required List<String> evidenceIds,
required String language, required String language,
required String userSessionToken, required String userSessionToken,
required String sessionId, required String sessionId,
required int gender,
}); });
Future<Either<Failure, GenericApiModel<TriageDataDetails>>> Future<Either<Failure, GenericApiModel<TriageDataDetails>>> getDiagnosisForTriage({
getDiagnosisForTriage({
required int age, required int age,
required String sex, required int gender,
required List<String> evidenceIds, required List<String> evidenceIds,
List<Map<String, String>>? triageEvidence, List<Map<String, String>>? triageEvidence,
required String language, required String language,
required String userSessionToken, required String userSessionToken,
required int gender,
required String sessionId, required String sessionId,
}); });
} }
@ -64,12 +56,10 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
final ApiClient apiClient; final ApiClient apiClient;
final LoggerService loggerService; final LoggerService loggerService;
SymptomsCheckerRepoImp( SymptomsCheckerRepoImp({required this.apiClient, required this.loggerService});
{required this.apiClient, required this.loggerService});
@override @override
Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>> Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>> getUserDetails({
getUserDetails({
required String userName, required String userName,
required String password, required String password,
}) async { }) async {
@ -92,11 +82,9 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) { onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try { try {
// Parse response if it's a string // Parse response if it's a string
final Map<String, dynamic> responseData = final Map<String, dynamic> responseData = response is String ? jsonDecode(response) : response;
response is String ? jsonDecode(response) : response;
SymptomsUserDetailsResponseModel symptomsUserDetailsResponseModel = SymptomsUserDetailsResponseModel symptomsUserDetailsResponseModel = SymptomsUserDetailsResponseModel.fromJson(responseData);
SymptomsUserDetailsResponseModel.fromJson(responseData);
apiResponse = GenericApiModel<SymptomsUserDetailsResponseModel>( apiResponse = GenericApiModel<SymptomsUserDetailsResponseModel>(
messageStatus: messageStatus ?? 1, messageStatus: messageStatus ?? 1,
@ -123,8 +111,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
} }
@override @override
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>> Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>> getBodySymptomsByName({
getBodySymptomsByName({
required List<String> organNames, required List<String> organNames,
required String userSessionToken, required String userSessionToken,
required int gender, required int gender,
@ -154,8 +141,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
}, },
onSuccess: (response, statusCode, {messageStatus, errorMessage}) { onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try { try {
BodySymptomResponseModel bodySymptomResponse = BodySymptomResponseModel bodySymptomResponse = BodySymptomResponseModel.fromJson(response);
BodySymptomResponseModel.fromJson(response);
apiResponse = GenericApiModel<BodySymptomResponseModel>( apiResponse = GenericApiModel<BodySymptomResponseModel>(
messageStatus: messageStatus ?? 1, messageStatus: messageStatus ?? 1,
@ -164,8 +150,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
data: bodySymptomResponse, data: bodySymptomResponse,
); );
} catch (e, stackTrace) { } catch (e, stackTrace) {
loggerService loggerService.logError("Error parsing GetBodySymptomsByName response: $e");
.logError("Error parsing GetBodySymptomsByName response: $e");
loggerService.logError("StackTrace: $stackTrace"); loggerService.logError("StackTrace: $stackTrace");
failure = DataParsingFailure(e.toString()); failure = DataParsingFailure(e.toString());
} }
@ -183,21 +168,19 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
} }
@override @override
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getRiskFactors({
getRiskFactors({
required int age, required int age,
required String sex, required int gender,
required List<String> evidenceIds, required List<String> evidenceIds,
required String language, required String language,
required String userSessionToken, required String userSessionToken,
required int gender,
required String sessionId, required String sessionId,
}) async { }) async {
final Map<String, dynamic> body = { final Map<String, dynamic> body = {
"age": { "age": {
"value": age, "value": age,
}, },
"sex": sex, "gender": gender,
"evidence": evidenceIds.map((id) => {"id": id}).toList(), "evidence": evidenceIds.map((id) => {"id": id}).toList(),
"language": language, "language": language,
"generalId": sessionId, "generalId": sessionId,
@ -225,11 +208,9 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) { onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try { try {
// Parse response if it's a string // Parse response if it's a string
final Map<String, dynamic> responseData = final Map<String, dynamic> responseData = response is String ? jsonDecode(response) : response;
response is String ? jsonDecode(response) : response;
RiskAndSuggestionsResponseModel riskFactorsResponse = RiskAndSuggestionsResponseModel riskFactorsResponse = RiskAndSuggestionsResponseModel.fromJson(responseData);
RiskAndSuggestionsResponseModel.fromJson(responseData);
apiResponse = GenericApiModel<RiskAndSuggestionsResponseModel>( apiResponse = GenericApiModel<RiskAndSuggestionsResponseModel>(
messageStatus: messageStatus ?? 1, messageStatus: messageStatus ?? 1,
@ -255,16 +236,14 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
} }
} }
Future<Either<Failure, GenericApiModel<TriageDataDetails>>> @override
getDiagnosisForTriage({ Future<Either<Failure, GenericApiModel<TriageDataDetails>>> getDiagnosisForTriage({
required int age, required int age,
required String sex, required int gender,
required List<String> evidenceIds, required List<String> evidenceIds,
List<Map<String, String>>? List<Map<String, String>>? triageEvidence, // Additional triage-specific evidence
triageEvidence, // Additional triage-specific evidence
required String language, required String language,
required String userSessionToken, required String userSessionToken,
required int gender,
required String sessionId, required String sessionId,
}) async { }) async {
// Build evidence list: combine initial symptoms with triage evidence // Build evidence list: combine initial symptoms with triage evidence
@ -284,7 +263,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
"age": { "age": {
"value": age, "value": age,
}, },
"sex": sex, "gender": gender,
"evidence": evidenceList, "evidence": evidenceList,
"language": language, "language": language,
"suggest_method": "diagnosis", "suggest_method": "diagnosis",
@ -313,13 +292,11 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) { onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try { try {
// Parse response if it's a string // Parse response if it's a string
final Map<String, dynamic> responseData = final Map<String, dynamic> responseData = response is String ? jsonDecode(response) : response;
response is String ? jsonDecode(response) : response;
final updatedResponseData = responseData['dataDetails']; final updatedResponseData = responseData['dataDetails'];
TriageDataDetails riskFactorsResponse = TriageDataDetails riskFactorsResponse = TriageDataDetails.fromJson(updatedResponseData);
TriageDataDetails.fromJson(updatedResponseData);
apiResponse = GenericApiModel<TriageDataDetails>( apiResponse = GenericApiModel<TriageDataDetails>(
messageStatus: messageStatus ?? 1, messageStatus: messageStatus ?? 1,
@ -328,8 +305,7 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
data: riskFactorsResponse, data: riskFactorsResponse,
); );
} catch (e, stackTrace) { } catch (e, stackTrace) {
loggerService loggerService.logError("Error parsing getDiagnosisForTriage response: $e");
.logError("Error parsing getDiagnosisForTriage response: $e");
loggerService.logError("StackTrace: $stackTrace"); loggerService.logError("StackTrace: $stackTrace");
failure = DataParsingFailure(e.toString()); failure = DataParsingFailure(e.toString());
} }
@ -347,21 +323,19 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
} }
@override @override
Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> Future<Either<Failure, GenericApiModel<RiskAndSuggestionsResponseModel>>> getSuggestions({
getSuggestions({
required int age, required int age,
required String sex, required int gender,
required List<String> evidenceIds, required List<String> evidenceIds,
required String language, required String language,
required String userSessionToken, required String userSessionToken,
required String sessionId, required String sessionId,
required int gender,
}) async { }) async {
final Map<String, dynamic> body = { final Map<String, dynamic> body = {
"age": { "age": {
"value": age, "value": age,
}, },
"sex": sex, "gender": gender,
"evidence": evidenceIds.map((id) => {"id": id}).toList(), "evidence": evidenceIds.map((id) => {"id": id}).toList(),
"language": language, "language": language,
"generalId": sessionId, "generalId": sessionId,
@ -389,11 +363,9 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
onSuccess: (response, statusCode, {messageStatus, errorMessage}) { onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try { try {
// Parse response if it's a string // Parse response if it's a string
final Map<String, dynamic> responseData = final Map<String, dynamic> responseData = response is String ? jsonDecode(response) : response;
response is String ? jsonDecode(response) : response;
RiskAndSuggestionsResponseModel riskFactorsResponse = RiskAndSuggestionsResponseModel riskFactorsResponse = RiskAndSuggestionsResponseModel.fromJson(responseData);
RiskAndSuggestionsResponseModel.fromJson(responseData);
apiResponse = GenericApiModel<RiskAndSuggestionsResponseModel>( apiResponse = GenericApiModel<RiskAndSuggestionsResponseModel>(
messageStatus: messageStatus ?? 1, messageStatus: messageStatus ?? 1,

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/data/organ_mapping_data.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/data/organ_mapping_data.dart';
@ -47,12 +47,9 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
TriageDataDetails? triageDataDetails; TriageDataDetails? triageDataDetails;
// Triage state // Triage state
int? int? _selectedTriageChoiceIndex; // Deprecated - keeping for backward compatibility
_selectedTriageChoiceIndex; // Deprecated - keeping for backward compatibility final Map<String, int> _selectedTriageChoicesByItemId = {}; // Map of itemId -> choiceIndex for multi-item questions
final Map<String, int> _selectedTriageChoicesByItemId = final List<Map<String, String>> _triageEvidenceList = []; // Store triage evidence with proper format
{}; // Map of itemId -> choiceIndex for multi-item questions
final List<Map<String, String>> _triageEvidenceList =
[]; // Store triage evidence with proper format
int _triageQuestionCount = 0; // Track number of triage questions answered int _triageQuestionCount = 0; // Track number of triage questions answered
// Selected risk factors tracking // Selected risk factors tracking
@ -66,8 +63,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
// User Info Flow State // User Info Flow State
int _userInfoCurrentPage = 0; int _userInfoCurrentPage = 0;
bool _isSinglePageEditMode = bool _isSinglePageEditMode = false; // Track if editing single page or full flow
false; // Track if editing single page or full flow
String? _selectedGender; String? _selectedGender;
DateTime? _dateOfBirth; DateTime? _dateOfBirth;
int? _selectedAge; int? _selectedAge;
@ -107,17 +103,14 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
String? get tooltipOrganId => _tooltipOrganId; String? get tooltipOrganId => _tooltipOrganId;
String get currentSessionAuthToken => String get currentSessionAuthToken => symptomsUserDetailsResponseModel?.tokenDetails?.authToken ?? "";
symptomsUserDetailsResponseModel?.tokenDetails?.authToken ?? "";
String get currentSessionId => String get currentSessionId => symptomsUserDetailsResponseModel?.sessionId ?? "";
symptomsUserDetailsResponseModel?.sessionId ?? "";
// Triage-related getters // Triage-related getters
bool get shouldStopTriage => triageDataDetails?.shouldStop ?? false; bool get shouldStopTriage => triageDataDetails?.shouldStop ?? false;
bool get hasEmergencyEvidence => bool get hasEmergencyEvidence => triageDataDetails?.hasEmergencyEvidence ?? false;
triageDataDetails?.hasEmergencyEvidence ?? false;
String? get currentInterviewToken => triageDataDetails?.interviewToken; String? get currentInterviewToken => triageDataDetails?.interviewToken;
@ -137,15 +130,13 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Check if all items in current question have been answered /// Check if all items in current question have been answered
bool get areAllTriageItemsAnswered { bool get areAllTriageItemsAnswered {
if (currentTriageQuestion?.items == null || if (currentTriageQuestion?.items == null || currentTriageQuestion!.items!.isEmpty) {
currentTriageQuestion!.items!.isEmpty) {
return false; return false;
} }
// Check if we have an answer for each item // Check if we have an answer for each item
for (var item in currentTriageQuestion!.items!) { for (var item in currentTriageQuestion!.items!) {
if (item.id != null && if (item.id != null && !_selectedTriageChoicesByItemId.containsKey(item.id)) {
!_selectedTriageChoicesByItemId.containsKey(item.id)) {
return false; return false;
} }
} }
@ -153,8 +144,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
} }
/// Get organs for current view /// Get organs for current view
List<OrganModel> get currentOrgans => List<OrganModel> get currentOrgans => OrganData.getOrgansForView(_currentView);
OrganData.getOrgansForView(_currentView);
/// Get all selected organs from both views /// Get all selected organs from both views
List<OrganModel> get selectedOrgans { List<OrganModel> get selectedOrgans {
@ -162,9 +152,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
...OrganData.frontViewOrgans, ...OrganData.frontViewOrgans,
...OrganData.backViewOrgans, ...OrganData.backViewOrgans,
]; ];
return allOrgans return allOrgans.where((organ) => _selectedOrganIds.contains(organ.id)).toList();
.where((organ) => _selectedOrganIds.contains(organ.id))
.toList();
} }
/// Check if any organs are selected /// Check if any organs are selected
@ -181,13 +169,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
} }
int get totalSelectedSymptomsCount { int get totalSelectedSymptomsCount {
return _selectedSymptomsByOrgan.values return _selectedSymptomsByOrgan.values.fold(0, (sum, symptomIds) => sum + symptomIds.length);
.fold(0, (sum, symptomIds) => sum + symptomIds.length);
} }
bool get hasSelectedSymptoms { bool get hasSelectedSymptoms {
return _selectedSymptomsByOrgan.values return _selectedSymptomsByOrgan.values.any((symptomIds) => symptomIds.isNotEmpty);
.any((symptomIds) => symptomIds.isNotEmpty);
} }
/// Get risk factors list /// Get risk factors list
@ -213,8 +199,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
} }
void toggleView() { void toggleView() {
_currentView = _currentView = _currentView == BodyView.front ? BodyView.back : BodyView.front;
_currentView == BodyView.front ? BodyView.back : BodyView.front;
notifyListeners(); notifyListeners();
} }
@ -317,8 +302,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
return; return;
} }
List<String> organNames = List<String> organNames = selectedOrgans.map((organ) => organ.name).toList();
selectedOrgans.map((organ) => organ.name).toList();
await getBodySymptomsByName( await getBodySymptomsByName(
organNames: organNames, organNames: organNames,
@ -368,8 +352,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
} }
} }
if (matchingOrganId != null && if (matchingOrganId != null && _selectedSymptomsByOrgan.containsKey(matchingOrganId)) {
_selectedSymptomsByOrgan.containsKey(matchingOrganId)) {
final selectedIds = _selectedSymptomsByOrgan[matchingOrganId]!; final selectedIds = _selectedSymptomsByOrgan[matchingOrganId]!;
if (organResult.bodySymptoms != null) { if (organResult.bodySymptoms != null) {
@ -420,10 +403,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Get all selected risk factors /// Get all selected risk factors
List<RiskAndSuggestionsItemModel> getAllSelectedRiskFactors() { List<RiskAndSuggestionsItemModel> getAllSelectedRiskFactors() {
return riskFactorsList return riskFactorsList.where((factor) => factor.id != null && _selectedRiskFactorIds.contains(factor.id)).toList();
.where((factor) =>
factor.id != null && _selectedRiskFactorIds.contains(factor.id))
.toList();
} }
/// Clear all risk factor selections /// Clear all risk factor selections
@ -456,12 +436,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
} }
// Extract symptom IDs // Extract symptom IDs
List<String> evidenceIds = List<String> evidenceIds = selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
await getRiskFactors( await getRiskFactors(
age: _selectedAge!, age: _selectedAge!,
sex: _selectedGender!.toLowerCase(), gender: _selectedGender!.toLowerCase() == "male" ? 1 : 2,
evidenceIds: evidenceIds, evidenceIds: evidenceIds,
sessionId: currentSessionId, sessionId: currentSessionId,
language: appState.isArabic() ? 'ar' : 'en', language: appState.isArabic() ? 'ar' : 'en',
@ -481,7 +460,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Call Risk Factors API /// Call Risk Factors API
Future<void> getRiskFactors({ Future<void> getRiskFactors({
required int age, required int age,
required String sex, required int gender,
required String sessionId, required String sessionId,
required List<String> evidenceIds, required List<String> evidenceIds,
required String language, required String language,
@ -493,12 +472,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
final result = await symptomsCheckerRepo.getRiskFactors( final result = await symptomsCheckerRepo.getRiskFactors(
age: age, age: age,
sex: sex, gender: gender,
evidenceIds: evidenceIds, evidenceIds: evidenceIds,
language: language, language: language,
sessionId: sessionId, sessionId: sessionId,
userSessionToken: currentSessionAuthToken, userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
); );
result.fold( result.fold(
@ -515,10 +493,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
if (apiResponse.messageStatus == 1 && apiResponse.data != null) { if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
riskFactorsResponse = apiResponse.data; riskFactorsResponse = apiResponse.data;
if (riskFactorsResponse != null && if (riskFactorsResponse != null && riskFactorsResponse!.dataDetails != null) {
riskFactorsResponse!.dataDetails != null) { RiskAndSuggestionsItemModel riskFactorItem = RiskAndSuggestionsItemModel(
RiskAndSuggestionsItemModel riskFactorItem =
RiskAndSuggestionsItemModel(
id: "not_applicable", id: "not_applicable",
commonName: "Not Applicable", commonName: "Not Applicable",
name: "Not Applicable", name: "Not Applicable",
@ -572,10 +548,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Get all selected risk factors /// Get all selected risk factors
List<RiskAndSuggestionsItemModel> getAllSelectedSuggestions() { List<RiskAndSuggestionsItemModel> getAllSelectedSuggestions() {
return suggestionsList return suggestionsList.where((factor) => factor.id != null && _selectedSuggestionsIds.contains(factor.id)).toList();
.where((factor) =>
factor.id != null && _selectedSuggestionsIds.contains(factor.id))
.toList();
} }
/// Clear all risk factor selections /// Clear all risk factor selections
@ -590,20 +563,15 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
// Add selected symptoms // Add selected symptoms
final selectedSymptoms = getAllSelectedSymptoms(); final selectedSymptoms = getAllSelectedSymptoms();
evidenceIds evidenceIds.addAll(selectedSymptoms.where((s) => s.id != null).map((s) => s.id!));
.addAll(selectedSymptoms.where((s) => s.id != null).map((s) => s.id!));
// Add selected risk factors (excluding "not_applicable") // Add selected risk factors (excluding "not_applicable")
final selectedRiskFactors = getAllSelectedRiskFactors(); final selectedRiskFactors = getAllSelectedRiskFactors();
evidenceIds.addAll(selectedRiskFactors evidenceIds.addAll(selectedRiskFactors.where((rf) => rf.id != null && rf.id != "not_applicable").map((rf) => rf.id!));
.where((rf) => rf.id != null && rf.id != "not_applicable")
.map((rf) => rf.id!));
// Add selected suggestions (excluding "not_applicable") // Add selected suggestions (excluding "not_applicable")
final selectedSuggestions = getAllSelectedSuggestions(); final selectedSuggestions = getAllSelectedSuggestions();
evidenceIds.addAll(selectedSuggestions evidenceIds.addAll(selectedSuggestions.where((s) => s.id != null && s.id != "not_applicable").map((s) => s.id!));
.where((s) => s.id != null && s.id != "not_applicable")
.map((s) => s.id!));
return evidenceIds; return evidenceIds;
} }
@ -632,23 +600,19 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
} }
// Extract symptom IDs // Extract symptom IDs
List<String> evidenceIds = List<String> evidenceIds = selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
selectedSymptoms.where((s) => s.id != null).map((s) => s.id!).toList();
// Get all selected symptoms // Get all selected symptoms
final selectedRisks = getAllSelectedRiskFactors(); final selectedRisks = getAllSelectedRiskFactors();
if (selectedRisks.isNotEmpty) { if (selectedRisks.isNotEmpty) {
List<String> evidenceRisksIds = selectedRisks List<String> evidenceRisksIds = selectedRisks.where((s) => s.id != null && s.id != "not_applicable").map((s) => s.id!).toList();
.where((s) => s.id != null && s.id != "not_applicable")
.map((s) => s.id!)
.toList();
evidenceIds.addAll(evidenceRisksIds); evidenceIds.addAll(evidenceRisksIds);
} }
await getSuggestions( await getSuggestions(
age: _selectedAge!, age: _selectedAge!,
sex: _selectedGender!.toLowerCase(), gender: _selectedGender!.toLowerCase() == "male" ? 1 : 2,
evidenceIds: evidenceIds, evidenceIds: evidenceIds,
language: appState.isArabic() ? 'ar' : 'en', language: appState.isArabic() ? 'ar' : 'en',
onSuccess: (response) { onSuccess: (response) {
@ -667,7 +631,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Call Suggestions API /// Call Suggestions API
Future<void> getSuggestions({ Future<void> getSuggestions({
required int age, required int age,
required String sex, required int gender,
required List<String> evidenceIds, required List<String> evidenceIds,
required String language, required String language,
Function(RiskAndSuggestionsResponseModel)? onSuccess, Function(RiskAndSuggestionsResponseModel)? onSuccess,
@ -678,12 +642,11 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
final result = await symptomsCheckerRepo.getSuggestions( final result = await symptomsCheckerRepo.getSuggestions(
age: age, age: age,
sex: sex, gender: gender,
evidenceIds: evidenceIds, evidenceIds: evidenceIds,
language: language, language: language,
sessionId: currentSessionId, sessionId: currentSessionId,
userSessionToken: currentSessionAuthToken, userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
); );
result.fold( result.fold(
@ -700,10 +663,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
if (apiResponse.messageStatus == 1 && apiResponse.data != null) { if (apiResponse.messageStatus == 1 && apiResponse.data != null) {
suggestionsResponse = apiResponse.data; suggestionsResponse = apiResponse.data;
if (suggestionsResponse != null && if (suggestionsResponse != null && suggestionsResponse!.dataDetails != null) {
suggestionsResponse!.dataDetails != null) { RiskAndSuggestionsItemModel riskFactorItem = RiskAndSuggestionsItemModel(
RiskAndSuggestionsItemModel riskFactorItem =
RiskAndSuggestionsItemModel(
id: "not_applicable", id: "not_applicable",
commonName: "Not Applicable", commonName: "Not Applicable",
name: "Not Applicable", name: "Not Applicable",
@ -730,7 +691,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Call Diagnosis API for Triage - This is called iteratively until shouldStop is true /// Call Diagnosis API for Triage - This is called iteratively until shouldStop is true
Future<void> getDiagnosisForTriage({ Future<void> getDiagnosisForTriage({
required int age, required int age,
required String sex, required int gender,
required List<String> evidenceIds, required List<String> evidenceIds,
List<Map<String, String>>? triageEvidence, List<Map<String, String>>? triageEvidence,
required String language, required String language,
@ -742,13 +703,12 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
final result = await symptomsCheckerRepo.getDiagnosisForTriage( final result = await symptomsCheckerRepo.getDiagnosisForTriage(
age: age, age: age,
sex: sex, gender: gender,
evidenceIds: evidenceIds, evidenceIds: evidenceIds,
triageEvidence: triageEvidence, triageEvidence: triageEvidence,
language: language, language: language,
sessionId: currentSessionId, sessionId: currentSessionId,
userSessionToken: currentSessionAuthToken, userSessionToken: currentSessionAuthToken,
gender: (selectedGender ?? "Male").toLowerCase() == "male" ? 1 : 2,
); );
result.fold( result.fold(
@ -804,7 +764,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
await getDiagnosisForTriage( await getDiagnosisForTriage(
age: _selectedAge!, age: _selectedAge!,
sex: _selectedGender!.toLowerCase(), gender: _selectedGender!.toLowerCase() == "male" ? 1 : 2,
evidenceIds: evidenceIds, evidenceIds: evidenceIds,
language: appState.isArabic() ? 'ar' : 'en', language: appState.isArabic() ? 'ar' : 'en',
onSuccess: (response) { onSuccess: (response) {
@ -941,8 +901,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
// Calculate age from date of birth // Calculate age from date of birth
final now = DateTime.now(); final now = DateTime.now();
int age = now.year - dateOfBirth.year; int age = now.year - dateOfBirth.year;
if (now.month < dateOfBirth.month || if (now.month < dateOfBirth.month || (now.month == dateOfBirth.month && now.day < dateOfBirth.day)) {
(now.month == dateOfBirth.month && now.day < dateOfBirth.day)) {
age--; age--;
} }
_selectedAge = age; _selectedAge = age;
@ -989,8 +948,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}) async { }) async {
isBodySymptomsLoading = true; isBodySymptomsLoading = true;
notifyListeners(); notifyListeners();
final result = await symptomsCheckerRepo.getUserDetails( final result = await symptomsCheckerRepo.getUserDetails(userName: userName, password: password);
userName: userName, password: password);
result.fold( result.fold(
(failure) async { (failure) async {

@ -50,7 +50,14 @@ class ServicesPage extends StatelessWidget {
late MedicalFileViewModel medicalFileViewModel; late MedicalFileViewModel medicalFileViewModel;
late final List<HmgServicesComponentModel> hmgServices = [ late final List<HmgServicesComponentModel> hmgServices = [
HmgServicesComponentModel(11, LocaleKeys.emergencyServices.tr(), "", AppAssets.emergency_services_icon, bgColor: AppColors.primaryRedColor, true, route: null, onTap: () async { HmgServicesComponentModel(
11,
LocaleKeys.emergencyServices.tr(),
"",
AppAssets.emergency_services_icon,
bgColor: AppColors.primaryRedColor,
true,
route: null, onTap: () async {
if (getIt.get<AppState>().isAuthenticated) { if (getIt.get<AppState>().isAuthenticated) {
getIt.get<EmergencyServicesViewModel>().flushData(); getIt.get<EmergencyServicesViewModel>().flushData();
getIt.get<EmergencyServicesViewModel>().getTransportationOrders( getIt.get<EmergencyServicesViewModel>().getTransportationOrders(
@ -59,7 +66,7 @@ class ServicesPage extends StatelessWidget {
getIt.get<EmergencyServicesViewModel>().getRRTOrders( getIt.get<EmergencyServicesViewModel>().getRRTOrders(
showLoader: false, showLoader: false,
); );
Navigator.of(GetIt.instance<NavigationService>().navigatorKey.currentContext!).push( Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute( CustomPageRoute(
page: EmergencyServicesPage(), page: EmergencyServicesPage(),
settings: const RouteSettings(name: '/EmergencyServicesPage'), settings: const RouteSettings(name: '/EmergencyServicesPage'),
@ -78,7 +85,8 @@ class ServicesPage extends StatelessWidget {
true, true,
route: AppRoutes.bookAppointmentPage, route: AppRoutes.bookAppointmentPage,
), ),
HmgServicesComponentModel(5, LocaleKeys.completeCheckup.tr(), "", AppAssets.comprehensiveCheckup, bgColor: AppColors.bgGreenColor, true, route: null, onTap: () async { HmgServicesComponentModel(
5, LocaleKeys.completeCheckup.tr(), "", AppAssets.comprehensiveCheckup, bgColor: AppColors.bgGreenColor, true, route: null, onTap: () async {
if (getIt.get<AppState>().isAuthenticated) { if (getIt.get<AppState>().isAuthenticated) {
getIt.get<NavigationService>().pushPageRoute(AppRoutes.comprehensiveCheckupPage); getIt.get<NavigationService>().pushPageRoute(AppRoutes.comprehensiveCheckupPage);
} else { } else {
@ -131,7 +139,7 @@ class ServicesPage extends StatelessWidget {
}, },
), ),
HmgServicesComponentModel( HmgServicesComponentModel(
11, LocaleKeys.eReferralServices.tr(), "", AppAssets.eReferral, bgColor: AppColors.eReferralCardColor, true, route: null, onTap: () async { 11, LocaleKeys.eReferralServices.tr(), "", AppAssets.eReferral, bgColor: AppColors.eReferralCardColor, true, route: null, onTap: () async {
if (getIt.get<AppState>().isAuthenticated) { if (getIt.get<AppState>().isAuthenticated) {
getIt.get<NavigationService>().pushPageRoute(AppRoutes.eReferralPage); getIt.get<NavigationService>().pushPageRoute(AppRoutes.eReferralPage);
} else { } else {
@ -393,19 +401,19 @@ class ServicesPage extends StatelessWidget {
? CustomButton( ? CustomButton(
height: 40.h, height: 40.h,
icon: AppAssets.recharge_icon, icon: AppAssets.recharge_icon,
iconSize: 16.w, iconSize: 16.w,
iconColor: AppColors.infoColor, iconColor: AppColors.infoColor,
textColor: AppColors.infoColor, textColor: AppColors.infoColor,
text: LocaleKeys.recharge.tr(), text: LocaleKeys.recharge.tr(),
borderWidth: 0.w, borderWidth: 0.w,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
borderColor: Colors.transparent, borderColor: Colors.transparent,
backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08), backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w), padding: EdgeInsets.all(8.w),
fontSize: 12.f, fontSize: 12.f,
onPressed: () { onPressed: () {
Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage())); Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage()));
}, },
) )
: SizedBox.shrink(), : SizedBox.shrink(),
], ],
@ -444,60 +452,60 @@ class ServicesPage extends StatelessWidget {
getIt.get<AppState>().isAuthenticated getIt.get<AppState>().isAuthenticated
? Wrap( ? Wrap(
spacing: -8.h, spacing: -8.h,
// runSpacing: 0.h, // runSpacing: 0.h,
children: [ children: [
Utils.buildImgWithAssets( Utils.buildImgWithAssets(
icon: AppAssets.babyGirlImg, icon: AppAssets.babyGirlImg,
height: 28.h, height: 28.h,
width: 28.w, width: 28.w,
border: 1, border: 1,
fit: BoxFit.contain, fit: BoxFit.contain,
borderRadius: 50.r, borderRadius: 50.r,
), ),
Utils.buildImgWithAssets( Utils.buildImgWithAssets(
icon: AppAssets.femaleImg, icon: AppAssets.femaleImg,
height: 28.h, height: 28.h,
width: 28.w, width: 28.w,
border: 1, border: 1,
borderRadius: 50.r, borderRadius: 50.r,
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
Utils.buildImgWithAssets( Utils.buildImgWithAssets(
icon: AppAssets.maleImg, icon: AppAssets.maleImg,
height: 28.h, height: 28.h,
width: 28.w, width: 28.w,
border: 1, border: 1,
borderRadius: 50.r, borderRadius: 50.r,
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
], ],
) )
: LocaleKeys.loginToViewMedicalFile.tr().toText12(fontWeight: FontWeight.w500, maxLine: 2), : LocaleKeys.loginToViewMedicalFile.tr().toText12(fontWeight: FontWeight.w500, maxLine: 2),
Spacer(), Spacer(),
getIt.get<AppState>().isAuthenticated getIt.get<AppState>().isAuthenticated
? CustomButton( ? CustomButton(
height: 40.h, height: 40.h,
icon: AppAssets.add_icon, icon: AppAssets.add_icon,
iconSize: 16.w, iconSize: 16.w,
iconColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor,
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
text: LocaleKeys.addMember.tr(), text: LocaleKeys.addMember.tr(),
borderWidth: 0.w, borderWidth: 0.w,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
borderColor: Colors.transparent, borderColor: Colors.transparent,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08), backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w), padding: EdgeInsets.all(8.w),
fontSize: 12.f, fontSize: 12.f,
onPressed: () { onPressed: () {
DialogService dialogService = getIt.get<DialogService>(); DialogService dialogService = getIt.get<DialogService>();
medicalFileViewModel.clearAuthValues(); medicalFileViewModel.clearAuthValues();
dialogService.showAddFamilyFileSheet( dialogService.showAddFamilyFileSheet(
label: LocaleKeys.addFamilyMember.tr(), label: LocaleKeys.addFamilyMember.tr(),
message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(), message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(),
onVerificationPress: () { onVerificationPress: () {
medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms); medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms);
}); });
}, },
) )
: SizedBox.shrink(), : SizedBox.shrink(),
], ],

@ -28,7 +28,6 @@ import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart'; import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart'; import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_queue_page.dart'; import 'package:hmg_patient_app_new/presentation/appointments/appointment_queue_page.dart';
@ -62,8 +61,6 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/routes/spring_page_route_builder.dart'; import 'package:hmg_patient_app_new/widgets/routes/spring_page_route_builder.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../active_medication/active_medication_page.dart';
import '../emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart'; import '../emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart';
class LandingPage extends StatefulWidget { class LandingPage extends StatefulWidget {
@ -394,22 +391,23 @@ class _LandingPageState extends State<LandingPage> {
layout: SwiperLayout.STACK, layout: SwiperLayout.STACK,
loop: true, loop: true,
itemWidth: MediaQuery.of(context).size.width - 48.h, itemWidth: MediaQuery.of(context).size.width - 48.h,
indicatorLayout: PageIndicatorLayout.COLOR, indicatorLayout: PageIndicatorLayout.COLOR,
axisDirection: AxisDirection.right, axisDirection: AxisDirection.right,
controller: _controller, controller: _controller,
itemHeight: 255.h, itemHeight: 255.h,
pagination: SwiperPagination( pagination: SwiperPagination(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
margin: EdgeInsets.only(top: 240.h + 8 + 24), margin: EdgeInsets.only(top: 240.h + 8 + 24),
builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor),
), ),
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return getIndexSwiperCard(index); return getIndexSwiperCard(index);
}, },
) )
: Container( : Container(
width: double.infinity, width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), decoration: RoundedRectangleBorder()
.toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Padding( child: Padding(
padding: EdgeInsets.all(16.h), padding: EdgeInsets.all(16.h),
child: Column( child: Column(
@ -469,7 +467,11 @@ class _LandingPageState extends State<LandingPage> {
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.10), backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.10),
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
), ),
Utils.buildSvgWithAssets(icon: AppAssets.appointment_checkin_icon, width: 24.h, height: 24.h, iconColor: AppColors.primaryRedColor), Utils.buildSvgWithAssets(
icon: AppAssets.appointment_checkin_icon,
width: 24.h,
height: 24.h,
iconColor: AppColors.primaryRedColor),
], ],
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
@ -690,10 +692,18 @@ class _LandingPageState extends State<LandingPage> {
myAppointmentsViewModel.patientQueueDetailsList.first.queueNo!.toText12(isBold: true), myAppointmentsViewModel.patientQueueDetailsList.first.queueNo!.toText12(isBold: true),
SizedBox(width: 8.w), SizedBox(width: 8.w),
AppCustomChipWidget( AppCustomChipWidget(
deleteIcon: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? AppAssets.call_for_vitals : AppAssets.call_for_doctor, deleteIcon: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1
labelText: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? LocaleKeys.callForVitalSigns.tr() : LocaleKeys.callForDoctor.tr(), ? AppAssets.call_for_vitals
iconColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? AppColors.primaryRedColor : AppColors.successColor, : AppAssets.call_for_doctor,
textColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 ? AppColors.primaryRedColor : AppColors.successColor, labelText: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1
? LocaleKeys.callForVitalSigns.tr()
: LocaleKeys.callForDoctor.tr(),
iconColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1
? AppColors.primaryRedColor
: AppColors.successColor,
textColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1
? AppColors.primaryRedColor
: AppColors.successColor,
iconSize: 14.w, iconSize: 14.w,
backgroundColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1 backgroundColor: myAppointmentsViewModel.patientQueueDetailsList.first.callType == 1
? AppColors.primaryRedColor.withValues(alpha: 0.1) ? AppColors.primaryRedColor.withValues(alpha: 0.1)
@ -707,7 +717,8 @@ class _LandingPageState extends State<LandingPage> {
: SizedBox(height: 12.h), : SizedBox(height: 12.h),
SizedBox(height: 5.h), SizedBox(height: 5.h),
CustomButton( CustomButton(
text: Utils.getCardButtonText(myAppointmentsViewModel.currentQueueStatus, myAppointmentsViewModel.currentPatientQueueDetails.roomNo ?? ""), text: Utils.getCardButtonText(
myAppointmentsViewModel.currentQueueStatus, myAppointmentsViewModel.currentPatientQueueDetails.roomNo ?? ""),
onPressed: () {}, onPressed: () {},
backgroundColor: Utils.getCardButtonColor(myAppointmentsViewModel.currentQueueStatus), backgroundColor: Utils.getCardButtonColor(myAppointmentsViewModel.currentQueueStatus),
borderColor: Utils.getCardButtonColor(myAppointmentsViewModel.currentQueueStatus).withValues(alpha: 0.01), borderColor: Utils.getCardButtonColor(myAppointmentsViewModel.currentQueueStatus).withValues(alpha: 0.01),
@ -761,7 +772,8 @@ class _LandingPageState extends State<LandingPage> {
SizedBox(width: 8.w), SizedBox(width: 8.w),
AppCustomChipWidget( AppCustomChipWidget(
icon: AppAssets.appointment_calendar_icon, icon: AppAssets.appointment_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(immediateLiveCareViewModel.patientLiveCareHistoryList[0].arrivalTime), false)), labelText: DateUtil.formatDateToDate(
DateUtil.convertStringToDate(immediateLiveCareViewModel.patientLiveCareHistoryList[0].arrivalTime), false)),
], ],
), ),
Utils.buildSvgWithAssets(icon: AppAssets.waiting_icon, width: 24.h, height: 24.h), Utils.buildSvgWithAssets(icon: AppAssets.waiting_icon, width: 24.h, height: 24.h),
@ -769,9 +781,12 @@ class _LandingPageState extends State<LandingPage> {
], ],
), ),
SizedBox(height: 10.h), SizedBox(height: 10.h),
LocaleKeys.halaFirstName.tr(namedArgs: {'firstName': appState.getAuthenticatedUser()!.firstName!}, context: context).toText16(isBold: true), LocaleKeys.halaFirstName
.tr(namedArgs: {'firstName': appState.getAuthenticatedUser()!.firstName!}, context: context).toText16(isBold: true),
SizedBox(height: 8.h), SizedBox(height: 8.h),
LocaleKeys.yourTurnIsAfterPatients.tr(namedArgs: {'count': immediateLiveCareViewModel.patientLiveCareHistoryList[0].patCount.toString()}, context: context).toText14(isBold: true), LocaleKeys.yourTurnIsAfterPatients.tr(
namedArgs: {'count': immediateLiveCareViewModel.patientLiveCareHistoryList[0].patCount.toString()},
context: context).toText14(isBold: true),
SizedBox(height: 8.h), SizedBox(height: 8.h),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -978,7 +993,6 @@ class _LandingPageState extends State<LandingPage> {
isCloseButtonVisible: true, isCloseButtonVisible: true,
child: StatefulBuilder( child: StatefulBuilder(
builder: (context, setState) { builder: (context, setState) {
return RateAppointmentDoctor(); return RateAppointmentDoctor();
}, },
), ),

@ -8,11 +8,8 @@ import 'package:hmg_patient_app_new/presentation/contact_us/feedback_page.dart';
import 'package:hmg_patient_app_new/presentation/hmg_services/services_page.dart'; import 'package:hmg_patient_app_new/presentation/hmg_services/services_page.dart';
import 'package:hmg_patient_app_new/presentation/home/landing_page.dart'; import 'package:hmg_patient_app_new/presentation/home/landing_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/user_info_selection.dart';
import 'package:hmg_patient_app_new/presentation/todo_section/todo_page.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/widgets/bottom_navigation/bottom_navigation.dart'; import 'package:hmg_patient_app_new/widgets/bottom_navigation/bottom_navigation.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
class LandingNavigation extends StatefulWidget { class LandingNavigation extends StatefulWidget {
const LandingNavigation({super.key}); const LandingNavigation({super.key});
@ -53,11 +50,7 @@ class _LandingNavigationState extends State<LandingNavigation> {
} }
if (_currentIndex == 3) { if (_currentIndex == 3) {
if (appState.isAuthenticated) { if (appState.isAuthenticated) {
Navigator.of(context).push( context.navigateWithName(AppRoutes.userInfoSelection);
CustomPageRoute(
page: UserInfoSelectionScreen(),
),
);
} else { } else {
Utils.openWebView( Utils.openWebView(
url: 'https://x.com/HMG', url: 'https://x.com/HMG',

@ -3,13 +3,14 @@ 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';
import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/conditions_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/triage_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/condition_card.dart'; import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/condition_card.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -45,7 +46,7 @@ class PossibleConditionsPage extends StatelessWidget {
); );
} }
Widget _buildPredictionsList(BuildContext context, List<ConditionsModel> conditions) { Widget _buildPredictionsList(BuildContext context, List<TriageCondition> conditions, List<String> symptoms) {
if (conditions.isEmpty) { if (conditions.isEmpty) {
return Center( return Center(
child: Padding( child: Padding(
@ -74,19 +75,13 @@ class PossibleConditionsPage extends StatelessWidget {
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
separatorBuilder: (context, index) => SizedBox(height: 16.h), separatorBuilder: (context, index) => SizedBox(height: 16.h),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final conditionModel = conditions[index]; final condition = conditions[index];
return ConditionCard( return ConditionCard(
icon: conditionModel.icon, condition: condition,
title: conditionModel.title, symptoms: symptoms,
percentage: conditionModel.percentage,
tagText: conditionModel.tagText,
clinic: conditionModel.clinic,
symptoms: conditionModel.symptoms,
description: conditionModel.description,
possibleConditionsSeverityEnum: conditionModel.possibleConditionsSeverityEnum,
onActionPressed: () { onActionPressed: () {
dialogService.showErrorBottomSheet( dialogService.showErrorBottomSheet(
message: 'We are not available for a week. May you Rest In Peace :(', message: 'icd10 Code is ${condition.conditionDetails?.icd10Code}. We need to get the clinics mapped against this code.',
); );
}, },
); );
@ -102,7 +97,7 @@ class PossibleConditionsPage extends StatelessWidget {
title: LocaleKeys.notice.tr(context: context), title: LocaleKeys.notice.tr(context: context),
context, context,
child: Utils.getWarningWidget( child: Utils.getWarningWidget(
loadingText: LocaleKeys.areYouSureYouWantToRestartOrganSelection.tr(context: context), loadingText: LocaleKeys.areYouSureYouWantToExitProgress.tr(context: context),
isShowActionButtons: true, isShowActionButtons: true,
onCancelTap: () => Navigator.pop(context), onCancelTap: () => Navigator.pop(context),
onConfirmTap: () => onConfirm(), onConfirmTap: () => onConfirm(),
@ -113,47 +108,88 @@ class PossibleConditionsPage extends StatelessWidget {
); );
} }
_restartOrganSelection(BuildContext context) async { Widget _buildInfoTile({required PossibleConditionsSeverityEnum severityEnum}) {
final symptomsCheckerVm = context.read<SymptomsCheckerViewModel>(); String title;
symptomsCheckerVm.reset(); String description;
context.pop(); Color dotColor;
await Future.delayed(Duration(seconds: 1)).whenComplete(() => context.pop());
}
_navigateToLandingPage() { switch (severityEnum) {
NavigationService navigationService = getIt.get<NavigationService>(); case PossibleConditionsSeverityEnum.monitorOnly:
navigationService.replaceAllRoutesAndNavigateToLanding(); title = "Monitor".needTranslation;
} description = "No need to seek medical advice. Just keep healthy routine.".needTranslation;
dotColor = AppColors.chipColorMonitor;
break;
case PossibleConditionsSeverityEnum.seekMedicalAdvice:
title = "Seek Medical Advice".needTranslation;
description = "Not emergency but better to monitor the symptoms.".needTranslation;
dotColor = AppColors.chipColorSeekMedicalAdvice;
break;
case PossibleConditionsSeverityEnum.emergency:
title = "Emergency".needTranslation;
description = "Need to consult doctor as soon as possible before getting too late.".needTranslation;
dotColor = AppColors.chipColorEmergency;
break;
}
_buildTrailingSection(BuildContext context) {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
height: 40.h, height: 14.h,
padding: EdgeInsets.all(8.w), width: 14.w,
child: Center( decoration: BoxDecoration(shape: BoxShape.circle, color: dotColor),
child: Utils.buildSvgWithAssets( ).paddingOnly(top: 3.h),
icon: AppAssets.refreshIcon, SizedBox(width: 8.w),
height: 20.h, Expanded(
width: 20.w, child: Column(
iconColor: AppColors.textColor, crossAxisAlignment: CrossAxisAlignment.start,
), children: [
title.toText14(weight: FontWeight.w600, color: AppColors.textColor),
SizedBox(height: 4.h),
description.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
],
), ),
).onPress(() => _buildConfirmationBottomSheet(context: context, onConfirm: () => _restartOrganSelection(context))), ),
Container(
height: 40.h,
padding: EdgeInsets.all(8.w),
child: Center(
child: Utils.buildSvgWithAssets(
icon: AppAssets.homeBorderedIcon,
height: 20.h,
width: 20.w,
iconColor: AppColors.textColor,
),
),
).onPress(() => _buildConfirmationBottomSheet(context: context, onConfirm: () => _navigateToLandingPage())),
], ],
).paddingSymmetrical(20.w, 0); );
}
_buildSeverityDetailsBottomsheet({required BuildContext context}) {
return showCommonBottomSheetWithoutHeight(
title: "Color Science".needTranslation,
context,
child: Container(
padding: EdgeInsets.all(16.w),
width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Column(
children: [
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.monitorOnly),
Divider(color: AppColors.bottomNAVBorder, height: 24.h, thickness: 1),
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.seekMedicalAdvice),
Divider(color: AppColors.bottomNAVBorder, height: 24.h, thickness: 1),
_buildInfoTile(severityEnum: PossibleConditionsSeverityEnum.emergency),
],
),
),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
_buildTrailingSection(BuildContext context) {
return Container(
height: 40.h,
padding: EdgeInsets.all(8.w),
child: Center(
child: Utils.buildSvgWithAssets(
icon: AppAssets.coloredDotsIcon,
height: 20.h,
width: 20.w,
),
),
).onPress(() => _buildSeverityDetailsBottomsheet(context: context));
} }
@override @override
@ -162,13 +198,32 @@ class PossibleConditionsPage extends StatelessWidget {
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView( body: CollapsingListView(
title: LocaleKeys.possibleConditions.tr(context: context), title: LocaleKeys.possibleConditions.tr(context: context),
leadingCallback: () => _buildConfirmationBottomSheet(
context: context,
onConfirm: () {
context.pop();
final SymptomsCheckerViewModel symptomsCheckerViewModel = context.read<SymptomsCheckerViewModel>();
symptomsCheckerViewModel.reset(); // Clear all symptoms checker data
final navigationService = getIt.get<NavigationService>();
navigationService.replaceAllRoutesAndNavigateToLanding();
},
),
trailing: _buildTrailingSection(context), trailing: _buildTrailingSection(context),
child: Consumer<SymptomsCheckerViewModel>( child: Consumer<SymptomsCheckerViewModel>(
builder: (context, symptomsCheckerViewModel, child) { builder: (context, symptomsCheckerViewModel, child) {
if (symptomsCheckerViewModel.isPossibleConditionsLoading || symptomsCheckerViewModel.isPossibleConditionsLoading) { if (symptomsCheckerViewModel.isPossibleConditionsLoading || symptomsCheckerViewModel.isTriageDiagnosisLoading) {
return _buildLoadingShimmer(); return _buildLoadingShimmer();
} }
return _buildPredictionsList(context, dummyConditions); // Get conditions directly from ViewModel
final conditions = symptomsCheckerViewModel.currentConditions ?? [];
// Get selected symptoms names for display
final symptoms = symptomsCheckerViewModel
.getAllSelectedSymptoms()
.map((s) => s.commonName ?? s.name ?? '')
.where((name) => name.isNotEmpty)
.take(3)
.toList();
return _buildPredictionsList(context, conditions, symptoms);
}, },
), ),
), ),

@ -196,7 +196,7 @@ class _RiskFactorsScreenState extends State<RiskFactorsScreen> {
border: Border.all(color: AppColors.bottomNAVBorder, width: 1), border: Border.all(color: AppColors.bottomNAVBorder, width: 1),
), ),
child: Text( child: Text(
'Not Applicable Risk Factor', 'Not Applicable Risk Factor'.needTranslation,
style: TextStyle(fontSize: 14.f, color: AppColors.textColor), style: TextStyle(fontSize: 14.f, color: AppColors.textColor),
), ),
).toShimmer2(isShow: true, radius: 24.r); ).toShimmer2(isShow: true, radius: 24.r);

@ -4,12 +4,12 @@ import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/body_symptom_response_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/body_symptom_response_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -82,10 +82,12 @@ class _SymptomsSelectorPageState extends State<SymptomsSelectorPage> {
title: LocaleKeys.symptomsSelector.tr(), title: LocaleKeys.symptomsSelector.tr(),
leadingCallback: () => _buildConfirmationBottomSheet( leadingCallback: () => _buildConfirmationBottomSheet(
context: context, context: context,
onConfirm: () => { onConfirm: () {
context.pop(), context.pop();
context.pop(), viewModel.reset(); // Clear all symptoms checker data
}), final navigationService = getIt.get<NavigationService>();
navigationService.replaceAllRoutesAndNavigateToLanding();
}),
child: viewModel.isBodySymptomsLoading child: viewModel.isBodySymptomsLoading
? _buildLoadingShimmer() ? _buildLoadingShimmer()
: viewModel.organSymptomsResults.isEmpty : viewModel.organSymptomsResults.isEmpty

@ -14,6 +14,7 @@ import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_v
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/custom_progress_bar.dart'; import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/custom_progress_bar.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -119,12 +120,14 @@ class _TriagePageState extends State<TriagePage> {
SizedBox(height: 8.h), SizedBox(height: 8.h),
LocaleKeys.emergencyTriage.tr(context: context).toText28(color: AppColors.whiteColor, isBold: true), LocaleKeys.emergencyTriage.tr(context: context).toText28(color: AppColors.whiteColor, isBold: true),
SizedBox(height: 8.h), SizedBox(height: 8.h),
LocaleKeys.emergencyEvidenceDetected.tr(context: context) LocaleKeys.emergencyEvidenceDetected.tr(context: context).toText14(color: AppColors.whiteColor, weight: FontWeight.w500),
.toText14(color: AppColors.whiteColor, weight: FontWeight.w500),
SizedBox(height: 24.h), SizedBox(height: 24.h),
CustomButton( CustomButton(
text: LocaleKeys.confirm.tr(context: context), text: LocaleKeys.confirm.tr(context: context),
onPressed: () async => Navigator.of(context).pop(), onPressed: () {
context.pop();
context.navigateWithName(AppRoutes.possibleConditionsPage);
},
backgroundColor: AppColors.whiteColor, backgroundColor: AppColors.whiteColor,
borderColor: AppColors.whiteColor, borderColor: AppColors.whiteColor,
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
@ -197,7 +200,7 @@ class _TriagePageState extends State<TriagePage> {
// Call API with updated evidence // Call API with updated evidence
viewModel.getDiagnosisForTriage( viewModel.getDiagnosisForTriage(
age: viewModel.selectedAge!, age: viewModel.selectedAge!,
sex: viewModel.selectedGender!.toLowerCase(), gender: viewModel.selectedGender!.toLowerCase() == "male" ? 1 : 2,
evidenceIds: initialEvidenceIds, evidenceIds: initialEvidenceIds,
triageEvidence: triageEvidence, triageEvidence: triageEvidence,
language: viewModel.appState.isArabic() ? 'ar' : 'en', language: viewModel.appState.isArabic() ? 'ar' : 'en',
@ -307,8 +310,10 @@ class _TriagePageState extends State<TriagePage> {
isShowActionButtons: true, isShowActionButtons: true,
onCancelTap: () => Navigator.pop(context), onCancelTap: () => Navigator.pop(context),
onConfirmTap: () { onConfirmTap: () {
Navigator.pop(context);
context.pop(); context.pop();
viewModel.reset(); // Clear all symptoms checker data
final navigationService = getIt.get<NavigationService>();
navigationService.replaceAllRoutesAndNavigateToLanding();
}, },
), ),
callBackFunc: () {}, callBackFunc: () {},

@ -16,14 +16,14 @@ import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class UserInfoSelectionScreen extends StatefulWidget { class UserInfoSelectionPage extends StatefulWidget {
const UserInfoSelectionScreen({super.key}); const UserInfoSelectionPage({super.key});
@override @override
State<UserInfoSelectionScreen> createState() => _UserInfoSelectionScreenState(); State<UserInfoSelectionPage> createState() => _UserInfoSelectionPageState();
} }
class _UserInfoSelectionScreenState extends State<UserInfoSelectionScreen> { class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -155,10 +155,12 @@ class _UserInfoSelectionScreenState extends State<UserInfoSelectionScreen> {
// Show age calculated from DOB (prefer viewModel's age, fallback to calculated from user's DOB) // Show age calculated from DOB (prefer viewModel's age, fallback to calculated from user's DOB)
int? displayAge = viewModel.selectedAge ?? userAgeFromDOB; int? displayAge = viewModel.selectedAge ?? userAgeFromDOB;
String ageText = displayAge != null ? "$displayAge ${LocaleKeys.years.tr(context: context)}" : LocaleKeys.notSet.tr(context: context); String ageText = displayAge != null ? "$displayAge ${LocaleKeys.years.tr(context: context)}" : LocaleKeys.notSet.tr(context: context);
String heightText = String heightText = viewModel.selectedHeight != null
viewModel.selectedHeight != null ? "${viewModel.selectedHeight!.round()} ${viewModel.isHeightCm ? 'cm' : 'ft'}" : LocaleKeys.notSet.tr(context: context); ? "${viewModel.selectedHeight!.round()} ${viewModel.isHeightCm ? 'cm' : 'ft'}"
String weightText = : LocaleKeys.notSet.tr(context: context);
viewModel.selectedWeight != null ? "${viewModel.selectedWeight!.round()} ${viewModel.isWeightKg ? 'kg' : 'lbs'}" : LocaleKeys.notSet.tr(context: context); String weightText = viewModel.selectedWeight != null
? "${viewModel.selectedWeight!.round()} ${viewModel.isWeightKg ? 'kg' : 'lbs'}"
: LocaleKeys.notSet.tr(context: context);
return Column( return Column(
children: [ children: [
@ -176,9 +178,9 @@ class _UserInfoSelectionScreenState extends State<UserInfoSelectionScreen> {
child: Column( child: Column(
children: [ children: [
LocaleKeys.helloIsYourInformationUpToDate.tr(namedArgs: {'name': name}).toText16( LocaleKeys.helloIsYourInformationUpToDate.tr(namedArgs: {'name': name}).toText16(
weight: FontWeight.w600, weight: FontWeight.w600,
color: AppColors.textColor, color: AppColors.textColor,
), ),
SizedBox(height: 32.h), SizedBox(height: 32.h),
_buildEditInfoTile( _buildEditInfoTile(
context: context, context: context,

@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/models/resp_models/triage_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/custom_progress_bar.dart'; import 'package:hmg_patient_app_new/presentation/symptoms_checker/widgets/custom_progress_bar.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
@ -12,33 +13,128 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
class ConditionCard extends StatelessWidget { class ConditionCard extends StatelessWidget {
final IconData icon; final TriageCondition condition;
final String title;
final int percentage;
final String tagText;
final String clinic;
final List<String> symptoms; final List<String> symptoms;
final String description;
final String? monitorNote;
final String? appointmentLabel;
final PossibleConditionsSeverityEnum possibleConditionsSeverityEnum;
final VoidCallback? onActionPressed; final VoidCallback? onActionPressed;
const ConditionCard({ const ConditionCard({
super.key, super.key,
required this.icon, required this.condition,
required this.title,
required this.percentage,
required this.tagText,
required this.clinic,
required this.symptoms, required this.symptoms,
required this.description,
this.monitorNote,
this.appointmentLabel,
required this.possibleConditionsSeverityEnum,
this.onActionPressed, this.onActionPressed,
}); });
/// Get title from condition
String get title => condition.commonName ?? condition.name ?? '';
/// Get percentage from probability (0-1 to 0-100)
int get percentage => ((condition.probability ?? 0) * 100).toInt();
/// Get clinic name from category
String get clinic => condition.conditionDetails?.category?.name ?? '';
/// Get description from hint
String get description => condition.conditionDetails?.hint ?? '';
/// Get severity enum based on triage level
PossibleConditionsSeverityEnum get severityEnum {
final triageLevel = condition.conditionDetails?.triageLevel;
if (triageLevel != null) {
switch (triageLevel) {
case TriageLevelEnum.emergencyAmbulance:
case TriageLevelEnum.emergency:
return PossibleConditionsSeverityEnum.emergency;
case TriageLevelEnum.consultation24:
case TriageLevelEnum.consultation:
return PossibleConditionsSeverityEnum.seekMedicalAdvice;
case TriageLevelEnum.selfCare:
return PossibleConditionsSeverityEnum.monitorOnly;
}
}
// Default based on probability
if (percentage >= 70) {
return PossibleConditionsSeverityEnum.seekMedicalAdvice;
} else {
return PossibleConditionsSeverityEnum.monitorOnly;
}
}
/// Get tag text based on triage level
String getTagText(BuildContext context) {
final triageLevel = condition.conditionDetails?.triageLevel;
if (triageLevel != null) {
switch (triageLevel) {
case TriageLevelEnum.emergencyAmbulance:
case TriageLevelEnum.emergency:
return LocaleKeys.emergency.tr(context: context);
case TriageLevelEnum.consultation24:
case TriageLevelEnum.consultation:
return "Seek Medical Advice".needTranslation;
case TriageLevelEnum.selfCare:
return LocaleKeys.monitor.tr(context: context);
}
}
// Default based on probability
if (percentage >= 70) {
return "Seek Medical Advice".needTranslation;
} else {
return LocaleKeys.monitor.tr(context: context);
}
}
/// Get monitor note if applicable
String? getMonitorNote(BuildContext context) {
if (severityEnum == PossibleConditionsSeverityEnum.monitorOnly) {
return "No need to visit doctor".needTranslation;
}
return null;
}
/// Get icon based on category name from API
IconData get icon {
final categoryName = condition.conditionDetails?.category?.name?.toLowerCase() ?? '';
if (categoryName.contains('cardio') || categoryName.contains('heart')) {
return Icons.favorite;
} else if (categoryName.contains('neuro') || categoryName.contains('brain')) {
return Icons.psychology_alt;
} else if (categoryName.contains('psychiatr') || categoryName.contains('mental')) {
return Icons.psychology;
} else if (categoryName.contains('eye') || categoryName.contains('ophthalmo')) {
return Icons.remove_red_eye;
} else if (categoryName.contains('ent') || categoryName.contains('ear')) {
return Icons.hearing;
} else if (categoryName.contains('derma') || categoryName.contains('skin')) {
return Icons.face;
} else if (categoryName.contains('ortho') || categoryName.contains('bone')) {
return Icons.accessibility_new;
} else if (categoryName.contains('gyneco') || categoryName.contains('obstet')) {
return Icons.pregnant_woman;
} else if (categoryName.contains('pediatr') || categoryName.contains('child')) {
return Icons.child_care;
} else if (categoryName.contains('surg')) {
return Icons.local_hospital;
} else if (categoryName.contains('pulmo') || categoryName.contains('lung') || categoryName.contains('respiratory')) {
return Icons.air;
} else if (categoryName.contains('gastro') || categoryName.contains('digest')) {
return Icons.restaurant;
} else if (categoryName.contains('nephro') || categoryName.contains('kidney')) {
return Icons.water_drop;
} else if (categoryName.contains('hemato') || categoryName.contains('blood')) {
return Icons.bloodtype;
} else if (categoryName.contains('infect') || categoryName.contains('virus')) {
return Icons.coronavirus;
} else if (categoryName.contains('emergency')) {
return Icons.emergency;
} else if (categoryName.contains('geriatr') || categoryName.contains('elder')) {
return Icons.elderly;
} else if (categoryName.contains('internal')) {
return Icons.medical_services;
}
return Icons.medical_services;
}
Color getChipColorBySeverityEnum(PossibleConditionsSeverityEnum possibleConditionsSeverityEnum) { Color getChipColorBySeverityEnum(PossibleConditionsSeverityEnum possibleConditionsSeverityEnum) {
switch (possibleConditionsSeverityEnum) { switch (possibleConditionsSeverityEnum) {
case PossibleConditionsSeverityEnum.seekMedicalAdvice: case PossibleConditionsSeverityEnum.seekMedicalAdvice:
@ -67,7 +163,7 @@ class ConditionCard extends StatelessWidget {
crossAxisAlignment: WrapCrossAlignment.center, crossAxisAlignment: WrapCrossAlignment.center,
children: [ children: [
for (int i = 0; i < symptoms.length; i++) ...[ for (int i = 0; i < symptoms.length; i++) ...[
Text(symptoms[i], style: TextStyle(color: AppColors.greyTextColor, fontWeight: FontWeight.w500, fontSize: 12.f)), "${symptoms[i]}".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
if (i != symptoms.length - 1) if (i != symptoms.length - 1)
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: 2.w), padding: EdgeInsets.symmetric(horizontal: 2.w),
@ -80,9 +176,12 @@ class ConditionCard extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// final monitorNote = getMonitorNote(context);
final tagText = getTagText(context);
return Container( return Container(
width: double.infinity, width: double.infinity,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -90,14 +189,14 @@ class ConditionCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
width: 48.w, width: 32.w,
height: 48.w, height: 32.w,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: getChipColorBySeverityEnum(possibleConditionsSeverityEnum).withValues(alpha: 0.2), color: getChipColorBySeverityEnum(severityEnum).withValues(alpha: 0.2),
borderRadius: 12.r, borderRadius: 8.r,
hasShadow: false, hasShadow: false,
), ),
child: Icon(icon, color: getChipTextColorBySeverityEnum(possibleConditionsSeverityEnum), size: 24.f), child: Icon(icon, color: getChipTextColorBySeverityEnum(severityEnum), size: 16.f),
), ),
SizedBox(width: 12.w), SizedBox(width: 12.w),
Expanded( Expanded(
@ -108,34 +207,23 @@ class ConditionCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: Text( child: title.toText18(weight: FontWeight.w600, color: AppColors.textColor),
title,
style: TextStyle(fontSize: 18.f, fontWeight: FontWeight.w600, color: AppColors.textColor),
overflow: TextOverflow.ellipsis,
),
), ),
AppCustomChipWidget( AppCustomChipWidget(
labelText: tagText, labelText: tagText,
backgroundColor: getChipColorBySeverityEnum(possibleConditionsSeverityEnum).withValues(alpha: 0.2), backgroundColor: getChipColorBySeverityEnum(severityEnum).withValues(alpha: 0.2),
textColor: getChipTextColorBySeverityEnum(possibleConditionsSeverityEnum), textColor: getChipTextColorBySeverityEnum(severityEnum),
), ),
], ],
), ),
CustomRoundedProgressBar( CustomRoundedProgressBar(
percentage: percentage, percentage: percentage,
height: 6.h, height: 6.h,
color: getChipColorBySeverityEnum(possibleConditionsSeverityEnum), color: getChipColorBySeverityEnum(severityEnum),
backgroundColor: AppColors.scaffoldBgColor, backgroundColor: AppColors.scaffoldBgColor,
titleWidget: Row( titleWidget: Row(
children: [ children: [
Text( "$percentage%".toText12(fontWeight: FontWeight.bold, color: getChipColorBySeverityEnum(severityEnum)),
"$percentage%",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12.f,
color: getChipColorBySeverityEnum(possibleConditionsSeverityEnum),
),
),
], ],
).paddingSymmetrical(0, 4.h), ).paddingSymmetrical(0, 4.h),
), ),
@ -148,50 +236,42 @@ class ConditionCard extends StatelessWidget {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( "Common Symptom".needTranslation.toText14(weight: FontWeight.w600, color: AppColors.textColor),
clinic,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14.f,
color: AppColors.textColor,
),
),
_buildSymptomsRow(), _buildSymptomsRow(),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Text(LocaleKeys.description.tr(context: context), style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14.f, color: AppColors.textColor)), LocaleKeys.description.tr(context: context).toText14(weight: FontWeight.bold, color: AppColors.textColor),
SizedBox(height: 2.h), SizedBox(height: 2.h),
Text(description, style: TextStyle(color: AppColors.greyTextColor, fontWeight: FontWeight.w500, fontSize: 12.f)), description.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
if (possibleConditionsSeverityEnum == PossibleConditionsSeverityEnum.emergency) if (severityEnum != PossibleConditionsSeverityEnum.monitorOnly)
CustomButton( CustomButton(
text: appointmentLabel ?? LocaleKeys.bookAppointment.tr(context: context), text: "Book Appointment".needTranslation,
onPressed: () { onPressed: () {
if (onActionPressed != null) { if (onActionPressed != null) {
onActionPressed!(); onActionPressed!();
} }
}, },
backgroundColor: AppColors.lightRedButtonColor, backgroundColor: AppColors.primaryRedColor,
borderColor: Colors.transparent, borderColor: Colors.transparent,
textColor: AppColors.primaryRedColor, textColor: AppColors.whiteColor,
fontSize: 16.f, fontSize: 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w), padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 48.h,
icon: AppAssets.add_icon, icon: AppAssets.add_icon,
iconColor: AppColors.primaryRedColor, height: 48.h,
iconSize: 18.h, iconColor: AppColors.whiteColor,
).paddingOnly(top: 16.w), ).paddingOnly(top: 16.w),
if (monitorNote != null)
Container( // if (monitorNote != null)
margin: EdgeInsets.only(top: 12.h), // Container(
child: AppCustomChipWidget( // margin: EdgeInsets.only(top: 12.h),
labelText: monitorNote!, // child: AppCustomChipWidget(
backgroundColor: AppColors.whiteColor, // labelText: monitorNote,
textColor: AppColors.textColor, // backgroundColor: AppColors.whiteColor,
padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h), // textColor: AppColors.textColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), // padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h),
), // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)),
), // ),
// ),
], ],
).paddingAll(16.w), ).paddingAll(16.w),
], ],

@ -8,6 +8,7 @@ import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointme
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/comprehensive_checkup_page.dart'; import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/comprehensive_checkup_page.dart';
import 'package:hmg_patient_app_new/presentation/covid19test/covid19_landing_page.dart'; import 'package:hmg_patient_app_new/presentation/covid19test/covid19_landing_page.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/new_e_referral.dart'; import 'package:hmg_patient_app_new/presentation/e_referral/new_e_referral.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/emergency_services_page.dart';
import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculators_page.dart'; import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculators_page.dart';
import 'package:hmg_patient_app_new/presentation/health_trackers/add_health_tracker_entry_page.dart'; import 'package:hmg_patient_app_new/presentation/health_trackers/add_health_tracker_entry_page.dart';
import 'package:hmg_patient_app_new/presentation/health_trackers/health_tracker_detail_page.dart'; import 'package:hmg_patient_app_new/presentation/health_trackers/health_tracker_detail_page.dart';
@ -30,16 +31,14 @@ import 'package:hmg_patient_app_new/presentation/vital_sign/vital_sign_page.dart
import 'package:hmg_patient_app_new/presentation/water_monitor/water_consumption_page.dart'; import 'package:hmg_patient_app_new/presentation/water_monitor/water_consumption_page.dart';
import 'package:hmg_patient_app_new/presentation/water_monitor/water_monitor_settings_page.dart'; import 'package:hmg_patient_app_new/presentation/water_monitor/water_monitor_settings_page.dart';
import 'package:hmg_patient_app_new/splashPage.dart'; import 'package:hmg_patient_app_new/splashPage.dart';
import 'package:provider/provider.dart';
import '../features/qr_parking/qr_parking_view_model.dart';
import '../presentation/covid19test/covid19_landing_page.dart';
import '../core/dependencies.dart'; import '../core/dependencies.dart';
import '../features/monthly_reports/monthly_reports_repo.dart'; import '../features/monthly_reports/monthly_reports_repo.dart';
import '../features/monthly_reports/monthly_reports_view_model.dart'; import '../features/monthly_reports/monthly_reports_view_model.dart';
import '../features/qr_parking/qr_parking_view_model.dart';
import '../presentation/parking/paking_page.dart'; import '../presentation/parking/paking_page.dart';
import '../services/error_handler_service.dart'; import '../services/error_handler_service.dart';
import 'package:provider/provider.dart';
class AppRoutes { class AppRoutes {
static const String initialRoute = '/initialRoute'; static const String initialRoute = '/initialRoute';
@ -84,8 +83,10 @@ class AppRoutes {
static const String addHealthTrackerEntryPage = '/addHealthTrackerEntryPage'; static const String addHealthTrackerEntryPage = '/addHealthTrackerEntryPage';
static const String healthTrackerDetailPage = '/healthTrackerDetailPage'; static const String healthTrackerDetailPage = '/healthTrackerDetailPage';
static Map<String, WidgetBuilder> get routes => // Emergency Services
{ static const String emergencyServicesPage = '/emergencyServicesPage';
static Map<String, WidgetBuilder> get routes => {
initialRoute: (context) => SplashPage(), initialRoute: (context) => SplashPage(),
loginScreen: (context) => LoginScreen(), loginScreen: (context) => LoginScreen(),
landingScreen: (context) => LandingNavigation(), landingScreen: (context) => LandingNavigation(),
@ -104,7 +105,7 @@ class AppRoutes {
triagePage: (context) => TriagePage(), triagePage: (context) => TriagePage(),
bloodDonationPage: (context) => BloodDonationPage(), bloodDonationPage: (context) => BloodDonationPage(),
bookAppointmentPage: (context) => BookAppointmentPage(), bookAppointmentPage: (context) => BookAppointmentPage(),
userInfoSelection: (context) => UserInfoSelectionScreen(), userInfoSelection: (context) => UserInfoSelectionPage(),
userInfoFlowManager: (context) => UserInfoFlowManager(), userInfoFlowManager: (context) => UserInfoFlowManager(),
smartWatches: (context) => SmartwatchInstructionsPage(), smartWatches: (context) => SmartwatchInstructionsPage(),
huaweiHealthExample: (context) => HuaweiHealthExample(), huaweiHealthExample: (context) => HuaweiHealthExample(),
@ -115,34 +116,28 @@ class AppRoutes {
healthConvertersPage: (context) => HealthCalculatorsPage(type: HealthCalConEnum.converter), healthConvertersPage: (context) => HealthCalculatorsPage(type: HealthCalConEnum.converter),
healthTrackersPage: (context) => HealthTrackersPage(), healthTrackersPage: (context) => HealthTrackersPage(),
vitalSign: (context) => VitalSignPage(), vitalSign: (context) => VitalSignPage(),
emergencyServicesPage: (context) => EmergencyServicesPage(),
addHealthTrackerEntryPage: (context) { addHealthTrackerEntryPage: (context) {
final args = ModalRoute final args = ModalRoute.of(context)?.settings.arguments as HealthTrackerTypeEnum?;
.of(context)
?.settings
.arguments as HealthTrackerTypeEnum?;
return AddHealthTrackerEntryPage( return AddHealthTrackerEntryPage(
trackerType: args ?? HealthTrackerTypeEnum.bloodSugar, trackerType: args ?? HealthTrackerTypeEnum.bloodSugar,
); );
}, },
healthTrackerDetailPage: (context) { healthTrackerDetailPage: (context) {
final args = ModalRoute final args = ModalRoute.of(context)?.settings.arguments as HealthTrackerTypeEnum?;
.of(context)
?.settings
.arguments as HealthTrackerTypeEnum?;
return HealthTrackerDetailPage( return HealthTrackerDetailPage(
trackerType: args ?? HealthTrackerTypeEnum.bloodSugar, trackerType: args ?? HealthTrackerTypeEnum.bloodSugar,
); );
}, },
monthlyReports: (context) => ChangeNotifierProvider(
monthlyReports: (context) => ChangeNotifierProvider( create: (_) => MonthlyReportsViewModel(
create: (_) => MonthlyReportsViewModel( monthlyReportsRepo: getIt<MonthlyReportsRepo>(),
monthlyReportsRepo: getIt<MonthlyReportsRepo>(), errorHandlerService: getIt<ErrorHandlerService>(),
errorHandlerService: getIt<ErrorHandlerService>(), ),
), ),
), qrParking: (context) => ChangeNotifierProvider<QrParkingViewModel>(
qrParking: (context) => ChangeNotifierProvider<QrParkingViewModel>( create: (_) => getIt<QrParkingViewModel>(),
create: (_) => getIt<QrParkingViewModel>(), child: const ParkingPage(),
child: const ParkingPage(),
) )
}; };
} }

@ -92,7 +92,7 @@ class AppColors {
// SymptomsChecker // SymptomsChecker
static const Color chipColorSeekMedicalAdvice = Color(0xFFFFAF15); // #FFAF15 static const Color chipColorSeekMedicalAdvice = Color(0xFFFFAF15); // #FFAF15
static const Color chipTextColorSeekMedicalAdvice = Color(0xFFAB7103); // #AB7103 static const Color chipTextColorSeekMedicalAdvice = Color(0xFFD48D05); // #AB7103
static const Color chipColorMonitor = Color(0xFF18C273); // #18C273 static const Color chipColorMonitor = Color(0xFF18C273); // #18C273
static const Color chipColorEmergency = Color(0xFFED1C2B); // #ED1C2B static const Color chipColorEmergency = Color(0xFFED1C2B); // #ED1C2B

@ -80,17 +80,14 @@ class CustomButton extends StatelessWidget {
), ),
Visibility( Visibility(
visible: text.isNotEmpty, visible: text.isNotEmpty,
child: Padding( child: Text(
padding: EdgeInsets.only(top: 0), text,
child: Text( overflow: textOverflow,
text, style: context.dynamicTextStyle(
overflow: textOverflow, fontSize: fontS,
style: context.dynamicTextStyle( color: isDisabled ? AppColors.greyTextColor : textColor,
fontSize: fontS, letterSpacing: 0,
color: isDisabled ? AppColors.greyTextColor : textColor, fontWeight: fontWeight,
letterSpacing: 0,
fontWeight: fontWeight,
),
), ),
), ),
), ),

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save