Merge pull request #88 from yaso-meth/QOL--Patent-Manager-Appointment-update

Pat Manager enhancement
This commit is contained in:
yaso-meth
2025-03-04 14:41:22 +02:00
committed by GitHub
20 changed files with 2980 additions and 438 deletions

View File

@@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_notification_apis.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
// import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; // import '../mih_components/mih_pop_up_messages/mih_error_message.dart';
// import '../mih_components/mih_pop_up_messages/mih_success_message.dart'; // import '../mih_components/mih_pop_up_messages/mih_success_message.dart';
@@ -317,6 +318,7 @@ class MIHApiCalls {
static Future<void> reapplyPatientAccessAPICall( static Future<void> reapplyPatientAccessAPICall(
String business_id, String business_id,
String app_id, String app_id,
bool personalSelected,
BusinessArguments args, BusinessArguments args,
BuildContext context, BuildContext context,
) async { ) async {
@@ -335,7 +337,8 @@ class MIHApiCalls {
}), }),
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
reapplyAccessRequestNotificationAPICall(app_id, args, context); MihNotificationApis.reapplyAccessRequestNotificationAPICall(
app_id, personalSelected, args, context);
//notification here //notification here
} else { } else {
internetConnectionPopUp(context); internetConnectionPopUp(context);
@@ -357,6 +360,7 @@ class MIHApiCalls {
String app_id, String app_id,
String type, String type,
String requested_by, String requested_by,
bool personalSelected,
BusinessArguments args, BusinessArguments args,
BuildContext context, BuildContext context,
) async { ) async {
@@ -377,7 +381,8 @@ class MIHApiCalls {
}), }),
); );
if (response.statusCode == 201) { if (response.statusCode == 201) {
addAccessRequestNotificationAPICall(app_id, requested_by, args, context); MihNotificationApis.addAccessRequestNotificationAPICall(
app_id, requested_by, personalSelected, args, context);
} else { } else {
internetConnectionPopUp(context); internetConnectionPopUp(context);
} }
@@ -431,248 +436,6 @@ class MIHApiCalls {
} }
} }
//================== Notifications ==========================================================================
/// This function is used to create notification to patient for access reviews
///
/// Patameters:-
/// String app_id,
/// String business_name,
/// BuildContext context,
///
/// Returns void. (ON SUCCESS 201 , NAVIGATE TO /patient-manager)
static Future<void> addAccessRequestNotificationAPICall(
String app_id,
String business_name,
BusinessArguments args,
BuildContext context,
) async {
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"notification_type": "Forever Access Request",
"notification_message":
"A new Forever Access Request has been sent by $business_name in order to access your Patient Profile. Please review request.",
"action_path": "/access-review",
}),
);
if (response.statusCode == 201) {
String message =
"A request has been sent to the patient advising that you have requested access to their profile. Only once access has been granted will you be able to book an appointment.";
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: BusinessArguments(
args.signedInUser,
args.businessUser,
args.business,
),
);
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
}
/// This function is used to create notification to patient for access reviews
///
/// Patameters:-
/// String app_id,
/// String business_name,
/// BuildContext context,
///
/// Returns void. (ON SUCCESS 201 , NAVIGATE TO /patient-manager)
static Future<void> reapplyAccessRequestNotificationAPICall(
String app_id,
BusinessArguments args,
BuildContext context,
) async {
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"notification_type": "Re-applying for Access",
"notification_message":
"${args.business!.Name} is re-applying for access to your Patient Profile. Please review request.",
"action_path": "/access-review",
}),
);
if (response.statusCode == 201) {
String message =
"A request has been sent to the patient advising that you have re-applied for access to their profile. Only once access has been granted will you be able to book an appointment.";
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: args,
);
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
}
/// This function is used to create notification to patient for access reviews
///
/// Patameters:-
/// String app_id,
/// String business_name,
/// String origDate_time,
/// String date,
/// String time,
/// BusinessArguments args,
/// BuildContext context,
///
/// Returns void. (ON SUCCESS 201 , NAVIGATE TO /patient-manager)
static Future<void> addRescheduledAppointmentNotificationAPICall(
String app_id,
String business_name,
String origDate_time,
String date,
String time,
BusinessArguments args,
BuildContext context,
) async {
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"notification_type": "Appointment Rescheduled",
"notification_message":
"Your appointment with $business_name for the ${origDate_time.replaceAll("T", " ").substring(0, origDate_time.length - 3)} has been rescheduled to the ${date} ${time}.",
"action_path": "/appointments",
}),
);
if (response.statusCode == 201) {
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: BusinessArguments(
args.signedInUser,
args.businessUser,
args.business,
),
);
String message = "The appointment has been successfully rescheduled.";
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
}
/// This function is used to create notification to patient for access reviews
///
/// Patameters:-
/// String app_id,
/// String business_name,
/// String origDate_time,
/// String date,
/// String time,
/// BusinessArguments args,
/// BuildContext context,
///
/// Returns void. (ON SUCCESS 201 , NAVIGATE TO /patient-manager)
static Future<void> addCancelledAppointmentNotificationAPICall(
String app_id,
String date_time,
BusinessArguments args,
BuildContext context,
) async {
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"notification_type": "Appointment Cancelled",
"notification_message":
"Your appointment with ${args.business!.Name} for the ${date_time.replaceAll("T", " ")} has been cancelled.",
"action_path": "/appointments",
}),
);
if (response.statusCode == 201) {
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: BusinessArguments(
args.signedInUser,
args.businessUser,
args.business,
),
);
String message =
"The appointment has been cancelled successfully. This means it will no longer be visible in your waiting room and calender.";
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
}
/// This function is used to create notification to patient for access reviews
///
/// Patameters:-
/// String app_id,
/// String business_name,
/// String origDate_time,
/// String date,
/// String time,
/// BusinessArguments args,
/// BuildContext context,
///
/// Returns void. (ON SUCCESS 201 , NAVIGATE TO /patient-manager)
static Future<void> addNewAppointmentNotificationAPICall(
String app_id,
String date,
String time,
BusinessArguments args,
BuildContext context,
) async {
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"notification_type": "New Appointment Booked",
"notification_message":
"An appointment with ${args.business!.Name} has been booked for the $date $time.",
"action_path": "/appointments",
}),
);
if (response.statusCode == 201) {
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: args,
);
String message =
"The appointment was been created successfully. This means it will now be visible in your waiting room and calender.";
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
}
//================== APPOINTMENT/ PATIENT QUEUE ========================================================================== //================== APPOINTMENT/ PATIENT QUEUE ==========================================================================
/// This function is used to fetch a list of appointments for a doctors office for a date. /// This function is used to fetch a list of appointments for a doctors office for a date.
@@ -755,6 +518,7 @@ class MIHApiCalls {
static Future<void> updateApointmentAPICall( static Future<void> updateApointmentAPICall(
int idpatient_queue, int idpatient_queue,
String app_id, String app_id,
bool personalSelected,
String business_name, String business_name,
String origDate_time, String origDate_time,
String date, String date,
@@ -774,8 +538,9 @@ class MIHApiCalls {
}), }),
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
addRescheduledAppointmentNotificationAPICall( MihNotificationApis.addRescheduledAppointmentNotificationAPICall(
app_id, app_id,
personalSelected,
business_name, business_name,
origDate_time, origDate_time,
date, date,
@@ -799,6 +564,7 @@ class MIHApiCalls {
static Future<void> deleteApointmentAPICall( static Future<void> deleteApointmentAPICall(
int idpatient_queue, int idpatient_queue,
String app_id, String app_id,
bool personalSelected,
String date_time, String date_time,
BusinessArguments args, BusinessArguments args,
BuildContext context, BuildContext context,
@@ -813,8 +579,9 @@ class MIHApiCalls {
//print("Here4"); //print("Here4");
//print(response.statusCode); //print(response.statusCode);
if (response.statusCode == 200) { if (response.statusCode == 200) {
addCancelledAppointmentNotificationAPICall( MihNotificationApis.addCancelledAppointmentNotificationAPICall(
app_id, app_id,
personalSelected,
date_time, date_time,
args, args,
context, context,
@@ -840,6 +607,7 @@ class MIHApiCalls {
static Future<void> addAppointmentAPICall( static Future<void> addAppointmentAPICall(
String business_id, String business_id,
String app_id, String app_id,
bool personalSelected,
String date, String date,
String time, String time,
BusinessArguments args, BusinessArguments args,
@@ -884,8 +652,9 @@ class MIHApiCalls {
// String time, // String time,
// BusinessArguments args, // BusinessArguments args,
// BuildContext context, // BuildContext context,
addNewAppointmentNotificationAPICall( MihNotificationApis.addNewAppointmentNotificationAPICall(
app_id, app_id,
personalSelected,
date, date,
time, time,
args, args,

View File

@@ -1,10 +1,12 @@
import 'dart:convert'; import 'dart:convert';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_notification_apis.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/app_user.dart'; import 'package:Mzansi_Innovation_Hub/mih_objects/app_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/appointment.dart'; import 'package:Mzansi_Innovation_Hub/mih_objects/appointment.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/arguments.dart'; import 'package:Mzansi_Innovation_Hub/mih_objects/arguments.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart'; import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business_user.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
// import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; // import '../mih_components/mih_pop_up_messages/mih_error_message.dart';
// import '../mih_components/mih_pop_up_messages/mih_success_message.dart'; // import '../mih_components/mih_pop_up_messages/mih_success_message.dart';
@@ -69,6 +71,7 @@ class MihMzansiCalendarApis {
/// Returns Future<List<Appointment>>. /// Returns Future<List<Appointment>>.
static Future<List<Appointment>> getBusinessAppointments( static Future<List<Appointment>> getBusinessAppointments(
String business_id, String business_id,
bool waitingRoom,
String date, String date,
) async { ) async {
//print("Patien manager page: $endpoint"); //print("Patien manager page: $endpoint");
@@ -88,6 +91,15 @@ class MihMzansiCalendarApis {
List<Appointment>.from(l.map((model) => Appointment.fromJson(model))); List<Appointment>.from(l.map((model) => Appointment.fromJson(model)));
//print("Here3"); //print("Here3");
//print(patientQueue); //print(patientQueue);
// if (waitingRoom == true) {
// businessAppointments = businessAppointments
// .where((element) => element.app_id != "")
// .toList();
// } else {
// businessAppointments = businessAppointments
// .where((element) => element.app_id == "")
// .toList();
// }
return businessAppointments; return businessAppointments;
} else { } else {
throw Exception('failed to fatch business appointments'); throw Exception('failed to fatch business appointments');
@@ -102,8 +114,12 @@ class MihMzansiCalendarApis {
/// BuildContext context, /// BuildContext context,
/// ///
/// Returns VOID (TRIGGERS NOTIGICATIOPN ON SUCCESS) /// Returns VOID (TRIGGERS NOTIGICATIOPN ON SUCCESS)
static Future<void> deleteLoyaltyCardAPICall( static Future<void> deleteAppointmentAPICall(
AppUser signedInUser, AppUser signedInUser,
bool personalSelected,
Business? business,
BusinessUser? businessUser,
bool inWaitingRoom,
int idappointments, int idappointments,
BuildContext context, BuildContext context,
) async { ) async {
@@ -119,10 +135,28 @@ class MihMzansiCalendarApis {
if (response.statusCode == 200) { if (response.statusCode == 200) {
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pop();
if (inWaitingRoom == true && personalSelected == false) {
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: PatManagerArguments(
signedInUser,
false,
business,
businessUser,
),
);
} else {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
'/calendar', '/calendar',
arguments: signedInUser, arguments: CalendarArguments(
signedInUser,
personalSelected,
business,
businessUser,
),
); );
}
String message = String message =
"The appointment has been deleted successfully. This means it will no longer be visible in your Calendar."; "The appointment has been deleted successfully. This means it will no longer be visible in your Calendar.";
successPopUp(message, context); successPopUp(message, context);
@@ -180,6 +214,7 @@ class MihMzansiCalendarApis {
signedInUser, signedInUser,
true, true,
null, null,
null,
), ),
); );
successPopUp(message, context); successPopUp(message, context);
@@ -204,6 +239,8 @@ class MihMzansiCalendarApis {
static Future<void> addBusinessAppointment( static Future<void> addBusinessAppointment(
AppUser signedInUser, AppUser signedInUser,
Business business, Business business,
BusinessUser businessUser,
bool inWaitingRoom,
String title, String title,
String description, String description,
String date, String date,
@@ -229,18 +266,33 @@ class MihMzansiCalendarApis {
Navigator.pop(context); Navigator.pop(context);
Navigator.pop(context); Navigator.pop(context);
Navigator.pop(context); Navigator.pop(context);
Navigator.pop(context);
String message = String message =
"Your appointment \"$title\" for the $date $title has been deleted."; "Your appointment \"$title\" for the $date $title has been deleted.";
// Navigator.pop(context); // Navigator.pop(context);
if (inWaitingRoom) {
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: PatManagerArguments(
signedInUser,
false,
business,
businessUser,
),
);
} else {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
'/calendar', '/calendar',
arguments: CalendarArguments( arguments: CalendarArguments(
signedInUser, signedInUser,
false, false,
business, business,
businessUser,
), ),
); );
}
successPopUp(message, context); successPopUp(message, context);
} else { } else {
Navigator.pop(context); Navigator.pop(context);
@@ -248,6 +300,60 @@ class MihMzansiCalendarApis {
} }
} }
/// This function is used to add an appointment to users mzansi Calendar.
///
/// Patameters:-
/// AppUser signedInUser,
/// String app_id,
/// String title,
/// String description,
/// String date,
/// String time,
/// BuildContext context,
///
/// Returns VOID (TRIGGERS SUCCESS pop up)
static Future<void> addPatientAppointment(
AppUser signedInUser,
bool personalSelected,
String patientAppId,
BusinessArguments businessArgs,
String title,
String description,
String date,
String time,
BuildContext context,
) async {
loadingPopUp(context);
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/appointment/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": patientAppId,
"business_id": businessArgs.business?.business_id,
"title": title,
"description": description,
"date": date,
"time": time,
}),
);
if (response.statusCode == 201) {
MihNotificationApis.addNewAppointmentNotificationAPICall(
patientAppId,
personalSelected,
date,
time,
businessArgs,
context,
);
// Navigator.pop(context);
} else {
Navigator.pop(context);
internetConnectionPopUp(context);
}
}
/// This function is used to update an appointment to users mzansi Calendar. /// This function is used to update an appointment to users mzansi Calendar.
/// ///
/// Patameters:- /// Patameters:-
@@ -263,6 +369,8 @@ class MihMzansiCalendarApis {
/// Returns VOID (TRIGGERS SUCCESS pop up) /// Returns VOID (TRIGGERS SUCCESS pop up)
static Future<void> updatePersonalAppointment( static Future<void> updatePersonalAppointment(
AppUser signedInUser, AppUser signedInUser,
Business? business,
BusinessUser? businessUser,
int idappointments, int idappointments,
String title, String title,
String description, String description,
@@ -294,7 +402,137 @@ class MihMzansiCalendarApis {
Navigator.pop(context); Navigator.pop(context);
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
'/calendar', '/calendar',
arguments: signedInUser, arguments: CalendarArguments(
signedInUser,
true,
business,
businessUser,
),
);
successPopUp(message, context);
} else {
Navigator.pop(context);
internetConnectionPopUp(context);
}
}
/// This function is used to update an appointment to users mzansi Calendar.
///
/// Patameters:-
/// AppUser signedInUser,
/// String app_id,
/// int idappointments,
/// String title,
/// String description,
/// String date,
/// String time,
/// BuildContext context,
///
/// Returns VOID (TRIGGERS SUCCESS pop up)
static Future<void> updateBusinessAppointment(
AppUser signedInUser,
Business? business,
BusinessUser? businessUser,
int idappointments,
String title,
String description,
String date,
String time,
BuildContext context,
) async {
loadingPopUp(context);
var response = await http.put(
Uri.parse("${AppEnviroment.baseApiUrl}/appointment/update/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"idappointments": idappointments,
"title": title,
"description": description,
"date": date,
"time": time,
}),
);
if (response.statusCode == 200) {
Navigator.pop(context);
Navigator.pop(context);
Navigator.pop(context);
String message =
"Your appointment \"$title\" has been updates to the $date $title.";
Navigator.pop(context);
Navigator.of(context).pushNamed(
'/calendar',
arguments: CalendarArguments(
signedInUser,
false,
business,
businessUser,
),
);
successPopUp(message, context);
} else {
Navigator.pop(context);
internetConnectionPopUp(context);
}
}
/// This function is used to update an appointment to users mzansi Calendar.
///
/// Patameters:-
/// AppUser signedInUser,
/// String app_id,
/// int idappointments,
/// String title,
/// String description,
/// String date,
/// String time,
/// BuildContext context,
///
/// Returns VOID (TRIGGERS SUCCESS pop up)
static Future<void> updatePatientAppointment(
AppUser signedInUser,
Business? business,
BusinessUser? businessUser,
int idappointments,
String title,
String description,
String date,
String time,
BuildContext context,
) async {
loadingPopUp(context);
var response = await http.put(
Uri.parse("${AppEnviroment.baseApiUrl}/appointment/update/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"idappointments": idappointments,
"title": title,
"description": description,
"date": date,
"time": time,
}),
);
if (response.statusCode == 200) {
Navigator.pop(context);
Navigator.pop(context);
Navigator.pop(context);
Navigator.pop(context);
String message =
"Your appointment \"$title\" has been updates to the $date $title.";
// Navigator.pop(context);
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: PatManagerArguments(
signedInUser,
false,
business,
businessUser,
),
); );
successPopUp(message, context); successPopUp(message, context);
} else { } else {

View File

@@ -0,0 +1,296 @@
import 'dart:convert';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_error_message.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_success_message.dart';
import 'package:Mzansi_Innovation_Hub/mih_env/env.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/arguments.dart';
import 'package:flutter/material.dart';
import 'package:supertokens_flutter/http.dart' as http;
class MihNotificationApis {
final baseAPI = AppEnviroment.baseApiUrl;
//================== Notifications ==========================================================================
/// This function is used to create notification to patient for access reviews
///
/// Patameters:-
/// String app_id,
/// String business_name,
/// BuildContext context,
///
/// Returns void. (ON SUCCESS 201 , NAVIGATE TO /patient-manager)
static Future<void> addAccessRequestNotificationAPICall(
String app_id,
String business_name,
bool personalSelected,
BusinessArguments args,
BuildContext context,
) async {
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"notification_type": "Forever Access Request",
"notification_message":
"A new Forever Access Request has been sent by $business_name in order to access your Patient Profile. Please review request.",
"action_path": "/access-review",
}),
);
if (response.statusCode == 201) {
String message =
"A request has been sent to the patient advising that you have requested access to their profile. Only once access has been granted will you be able to book an appointment.";
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: PatManagerArguments(
args.signedInUser,
personalSelected,
args.business,
args.businessUser,
),
);
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
}
/// This function is used to create notification to patient for access reviews
///
/// Patameters:-
/// String app_id,
/// String business_name,
/// BuildContext context,
///
/// Returns void. (ON SUCCESS 201 , NAVIGATE TO /patient-manager)
static Future<void> reapplyAccessRequestNotificationAPICall(
String app_id,
bool personalSelected,
BusinessArguments args,
BuildContext context,
) async {
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"notification_type": "Re-applying for Access",
"notification_message":
"${args.business!.Name} is re-applying for access to your Patient Profile. Please review request.",
"action_path": "/access-review",
}),
);
if (response.statusCode == 201) {
String message =
"A request has been sent to the patient advising that you have re-applied for access to their profile. Only once access has been granted will you be able to book an appointment.";
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: PatManagerArguments(
args.signedInUser,
personalSelected,
args.business,
args.businessUser,
),
);
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
}
/// This function is used to create notification to patient for access reviews
///
/// Patameters:-
/// String app_id,
/// String business_name,
/// String origDate_time,
/// String date,
/// String time,
/// BusinessArguments args,
/// BuildContext context,
///
/// Returns void. (ON SUCCESS 201 , NAVIGATE TO /patient-manager)
static Future<void> addRescheduledAppointmentNotificationAPICall(
String app_id,
bool personalSelected,
String business_name,
String origDate_time,
String date,
String time,
BusinessArguments args,
BuildContext context,
) async {
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"notification_type": "Appointment Rescheduled",
"notification_message":
"Your appointment with $business_name for the ${origDate_time.replaceAll("T", " ").substring(0, origDate_time.length - 3)} has been rescheduled to the ${date} ${time}.",
"action_path": "/appointments",
}),
);
if (response.statusCode == 201) {
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: PatManagerArguments(
args.signedInUser,
personalSelected,
args.business,
args.businessUser,
),
);
String message = "The appointment has been successfully rescheduled.";
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
}
/// This function is used to create notification to patient for access reviews
///
/// Patameters:-
/// String app_id,
/// String business_name,
/// String origDate_time,
/// String date,
/// String time,
/// BusinessArguments args,
/// BuildContext context,
///
/// Returns void. (ON SUCCESS 201 , NAVIGATE TO /patient-manager)
static Future<void> addCancelledAppointmentNotificationAPICall(
String app_id,
bool personalSelected,
String date_time,
BusinessArguments args,
BuildContext context,
) async {
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"notification_type": "Appointment Cancelled",
"notification_message":
"Your appointment with ${args.business!.Name} for the ${date_time.replaceAll("T", " ")} has been cancelled.",
"action_path": "/appointments",
}),
);
if (response.statusCode == 201) {
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: PatManagerArguments(
args.signedInUser,
personalSelected,
args.business,
args.businessUser,
),
);
String message =
"The appointment has been cancelled successfully. This means it will no longer be visible in your waiting room and calender.";
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
}
/// This function is used to create notification to patient for access reviews
///
/// Patameters:-
/// String app_id,
/// String business_name,
/// String origDate_time,
/// String date,
/// String time,
/// BusinessArguments args,
/// BuildContext context,
///
/// Returns void. (ON SUCCESS 201 , NAVIGATE TO /patient-manager)
static Future<void> addNewAppointmentNotificationAPICall(
String app_id,
bool personalSelected,
String date,
String time,
BusinessArguments args,
BuildContext context,
) async {
var response = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"notification_type": "New Appointment Booked",
"notification_message":
"An appointment with ${args.business!.Name} has been booked for the $date $time.",
"action_path": "/appointments",
}),
);
if (response.statusCode == 201) {
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: PatManagerArguments(
args.signedInUser,
personalSelected,
args.business,
args.businessUser,
),
);
String message =
"The appointment was been created successfully. This means it will now be visible in your waiting room and calender.";
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
}
//================== POP UPS ==========================================================================
static void internetConnectionPopUp(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(
errorType: "Internet Connection",
);
},
);
}
static void successPopUp(String message, BuildContext context) {
showDialog(
context: context,
builder: (context) {
return MIHSuccessMessage(
successType: "Success",
successMessage: message,
);
},
);
}
}

View File

@@ -174,10 +174,26 @@ class CalendarArguments {
final AppUser signedInUser; final AppUser signedInUser;
final bool personalSelected; final bool personalSelected;
final Business? business; final Business? business;
final BusinessUser? businessUser;
CalendarArguments( CalendarArguments(
this.signedInUser, this.signedInUser,
this.personalSelected, this.personalSelected,
this.business, this.business,
this.businessUser,
);
}
class PatManagerArguments {
final AppUser signedInUser;
final bool personalSelected;
final Business? business;
final BusinessUser? businessUser;
PatManagerArguments(
this.signedInUser,
this.personalSelected,
this.business,
this.businessUser,
); );
} }

View File

@@ -8,15 +8,13 @@ import 'package:Mzansi_Innovation_Hub/mih_components/mih_layout/mih_window.dart'
import 'package:Mzansi_Innovation_Hub/mih_components/mih_package/mih-app_tool_body.dart'; import 'package:Mzansi_Innovation_Hub/mih_components/mih_package/mih-app_tool_body.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_error_message.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/appointment.dart'; import 'package:Mzansi_Innovation_Hub/mih_objects/appointment.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/arguments.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart'; import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/calendar/builder/build_appointment_list.dart'; import 'package:Mzansi_Innovation_Hub/mih_packages/calendar/builder/build_appointment_list.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../main.dart'; import '../../main.dart';
import '../../mih_components/mih_calendar.dart'; import '../../mih_components/mih_calendar.dart';
import '../../mih_components/mih_layout/mih_action.dart';
import '../../mih_components/mih_layout/mih_header.dart';
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import '../../mih_env/env.dart'; import '../../mih_env/env.dart';
import '../../mih_objects/app_user.dart'; import '../../mih_objects/app_user.dart';
@@ -24,12 +22,14 @@ import '../../mih_objects/app_user.dart';
class Appointments extends StatefulWidget { class Appointments extends StatefulWidget {
final AppUser signedInUser; final AppUser signedInUser;
final Business? business; final Business? business;
final BusinessUser? businessUser;
final bool personalSelected; final bool personalSelected;
const Appointments({ const Appointments({
super.key, super.key,
required this.signedInUser, required this.signedInUser,
required this.business, required this.business,
required this.businessUser,
required this.personalSelected, required this.personalSelected,
}); });
@@ -38,8 +38,8 @@ class Appointments extends StatefulWidget {
} }
class _PatientAccessRequestState extends State<Appointments> { class _PatientAccessRequestState extends State<Appointments> {
TextEditingController filterController = TextEditingController(); TextEditingController selectedAppointmentDateController =
TextEditingController appointmentDateController = TextEditingController(); TextEditingController();
final TextEditingController _appointmentTitleController = final TextEditingController _appointmentTitleController =
TextEditingController(); TextEditingController();
final TextEditingController _appointmentDescriptionIDController = final TextEditingController _appointmentDescriptionIDController =
@@ -50,12 +50,6 @@ class _PatientAccessRequestState extends State<Appointments> {
TextEditingController(); TextEditingController();
String baseUrl = AppEnviroment.baseApiUrl; String baseUrl = AppEnviroment.baseApiUrl;
String errorCode = "";
String errorBody = "";
String datefilter = "";
String accessFilter = "";
bool forceRefresh = false;
late String selectedDropdown;
String selectedDay = DateTime.now().toString().split(" ")[0]; String selectedDay = DateTime.now().toString().split(" ")[0];
late Future<List<Appointment>> personalAppointmentResults; late Future<List<Appointment>> personalAppointmentResults;
@@ -68,8 +62,13 @@ class _PatientAccessRequestState extends State<Appointments> {
child: BuildAppointmentList( child: BuildAppointmentList(
appointmentList: appointmentList, appointmentList: appointmentList,
signedInUser: widget.signedInUser, signedInUser: widget.signedInUser,
business: widget.business,
businessUser: widget.businessUser,
personalSelected: widget.personalSelected,
inWaitingRoom: false,
titleController: _appointmentTitleController, titleController: _appointmentTitleController,
descriptionIDController: _appointmentDescriptionIDController, descriptionIDController: _appointmentDescriptionIDController,
patientIdController: null,
dateController: _appointmentDateController, dateController: _appointmentDateController,
timeController: _appointmentTimeController, timeController: _appointmentTimeController,
), ),
@@ -187,6 +186,8 @@ class _PatientAccessRequestState extends State<Appointments> {
MihMzansiCalendarApis.addBusinessAppointment( MihMzansiCalendarApis.addBusinessAppointment(
widget.signedInUser, widget.signedInUser,
widget.business!, widget.business!,
widget.businessUser!,
false,
_appointmentTitleController.text, _appointmentTitleController.text,
_appointmentDescriptionIDController.text, _appointmentDescriptionIDController.text,
_appointmentDateController.text, _appointmentDateController.text,
@@ -227,6 +228,7 @@ class _PatientAccessRequestState extends State<Appointments> {
if (widget.personalSelected == false) { if (widget.personalSelected == false) {
appointmentResults = MihMzansiCalendarApis.getBusinessAppointments( appointmentResults = MihMzansiCalendarApis.getBusinessAppointments(
widget.business!.business_id, widget.business!.business_id,
false,
selectedDay, selectedDay,
); );
} else { } else {
@@ -238,36 +240,6 @@ class _PatientAccessRequestState extends State<Appointments> {
}); });
} }
MIHAction getActionButton() {
return MIHAction(
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).popAndPushNamed(
'/',
arguments: AuthArguments(true, false),
);
},
);
}
MIHHeader getHeader() {
return const MIHHeader(
headerAlignment: MainAxisAlignment.center,
headerItems: [
Text(
"Appointments",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 25,
),
),
],
);
}
Widget getBody() { Widget getBody() {
return Stack( return Stack(
children: [ children: [
@@ -286,7 +258,7 @@ class _PatientAccessRequestState extends State<Appointments> {
setDate: (value) { setDate: (value) {
setState(() { setState(() {
selectedDay = value; selectedDay = value;
appointmentDateController.text = selectedDay; selectedAppointmentDateController.text = selectedDay;
}); });
}), }),
// Divider( // Divider(
@@ -348,8 +320,7 @@ class _PatientAccessRequestState extends State<Appointments> {
@override @override
void dispose() { void dispose() {
filterController.dispose(); selectedAppointmentDateController.dispose();
appointmentDateController.dispose();
_appointmentDateController.dispose(); _appointmentDateController.dispose();
_appointmentTimeController.dispose(); _appointmentTimeController.dispose();
_appointmentTitleController.dispose(); _appointmentTitleController.dispose();
@@ -359,11 +330,12 @@ class _PatientAccessRequestState extends State<Appointments> {
@override @override
void initState() { void initState() {
appointmentDateController.addListener(checkforchange); selectedAppointmentDateController.addListener(checkforchange);
setState(() { setState(() {
if (widget.personalSelected == false) { if (widget.personalSelected == false) {
appointmentResults = MihMzansiCalendarApis.getBusinessAppointments( appointmentResults = MihMzansiCalendarApis.getBusinessAppointments(
widget.business!.business_id, widget.business!.business_id,
false,
selectedDay, selectedDay,
); );
} else { } else {

View File

@@ -11,13 +11,20 @@ import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_err
import 'package:Mzansi_Innovation_Hub/mih_env/env.dart'; import 'package:Mzansi_Innovation_Hub/mih_env/env.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/app_user.dart'; import 'package:Mzansi_Innovation_Hub/mih_objects/app_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/appointment.dart'; import 'package:Mzansi_Innovation_Hub/mih_objects/appointment.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business_user.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class BuildAppointmentList extends StatefulWidget { class BuildAppointmentList extends StatefulWidget {
final List<Appointment> appointmentList; final List<Appointment> appointmentList;
final AppUser signedInUser; final AppUser signedInUser;
final Business? business;
final BusinessUser? businessUser;
final bool personalSelected;
final bool inWaitingRoom;
final TextEditingController titleController; final TextEditingController titleController;
final TextEditingController descriptionIDController; final TextEditingController descriptionIDController;
final TextEditingController? patientIdController;
final TextEditingController dateController; final TextEditingController dateController;
final TextEditingController timeController; final TextEditingController timeController;
@@ -25,8 +32,13 @@ class BuildAppointmentList extends StatefulWidget {
super.key, super.key,
required this.appointmentList, required this.appointmentList,
required this.signedInUser, required this.signedInUser,
required this.business,
required this.businessUser,
required this.personalSelected,
required this.inWaitingRoom,
required this.titleController, required this.titleController,
required this.descriptionIDController, required this.descriptionIDController,
required this.patientIdController,
required this.dateController, required this.dateController,
required this.timeController, required this.timeController,
}); });
@@ -37,6 +49,7 @@ class BuildAppointmentList extends StatefulWidget {
class _BuildAppointmentListState extends State<BuildAppointmentList> { class _BuildAppointmentListState extends State<BuildAppointmentList> {
String baseAPI = AppEnviroment.baseApiUrl; String baseAPI = AppEnviroment.baseApiUrl;
TextEditingController patientIdController = TextEditingController();
TextEditingController dateController = TextEditingController(); TextEditingController dateController = TextEditingController();
TextEditingController timeController = TextEditingController(); TextEditingController timeController = TextEditingController();
TextEditingController idController = TextEditingController(); TextEditingController idController = TextEditingController();
@@ -122,7 +135,11 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
.split('T')[1] .split('T')[1]
.substring(0, 5); .substring(0, 5);
}); });
if (widget.inWaitingRoom == false) {
appointmentDetailsWindow(index); appointmentDetailsWindow(index);
} else {
waitingRiinAppointmentDetailsWindow(index);
}
}, },
), ),
), ),
@@ -233,6 +250,120 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
); );
} }
void waitingRiinAppointmentDetailsWindow(int index) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return MIHWindow(
fullscreen: false,
windowTitle: "Appointment Details",
windowTools: [
Visibility(
visible: canEditAppointment(index),
child: IconButton(
onPressed: () {
deleteAppointmentConfirmationWindow(index);
},
icon: const Icon(Icons.delete),
),
),
],
onWindowTapClose: () {
Navigator.of(context).pop();
widget.dateController.clear();
widget.timeController.clear();
widget.titleController.clear();
widget.descriptionIDController.clear();
},
windowBody: [
SizedBox(
// width: 500,
child: MIHTextField(
controller: widget.titleController,
hintText: "Title",
editable: false,
required: false,
),
),
const SizedBox(height: 10),
SizedBox(
// width: 500,
child: MIHTextField(
controller: widget.titleController,
hintText: "Patient ID Number",
editable: false,
required: false,
),
),
const SizedBox(height: 10),
SizedBox(
// width: 500,
child: MIHTextField(
controller: widget.dateController,
hintText: "Date",
editable: false,
required: false,
)),
const SizedBox(height: 10),
SizedBox(
// width: 500,
child: MIHTextField(
controller: widget.timeController,
hintText: "Time",
editable: false,
required: false,
)),
const SizedBox(height: 10),
SizedBox(
// width: 500,
height: 250,
child: MIHMLTextField(
controller: widget.descriptionIDController,
hintText: "Description",
editable: false,
required: false,
),
),
const SizedBox(height: 20),
Visibility(
visible: canEditAppointment(index),
child: SizedBox(
width: 500,
height: 50,
child: MIHButton(
onTap: () {
appointmentUpdateWindow(index);
},
buttonText: "Edit",
buttonColor:
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(),
),
),
),
// SizedBox(
// width: 500,
// height: 50,
// child: MIHButton(
// onTap: () {
// addAppointmentCall();
// checkforchange();
// },
// buttonText: "Add",
// buttonColor:
// MzanziInnovationHub.of(context)!.theme.successColor(),
// textColor:
// MzanziInnovationHub.of(context)!.theme.primaryColor(),
// ),
// ),
],
);
},
);
}
void appointmentUpdateWindow(int index) { void appointmentUpdateWindow(int index) {
showDialog( showDialog(
context: context, context: context,
@@ -315,33 +446,33 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
MzanziInnovationHub.of(context)!.theme.primaryColor(), MzanziInnovationHub.of(context)!.theme.primaryColor(),
), ),
), ),
SizedBox( // SizedBox(
width: 500, // width: 500,
height: 50, // height: 50,
child: MIHButton( // child: MIHButton(
onTap: () { // onTap: () {
setState(() { // setState(() {
widget.titleController.text = // widget.titleController.text =
widget.appointmentList[index].title; // widget.appointmentList[index].title;
widget.descriptionIDController.text = // widget.descriptionIDController.text =
widget.appointmentList[index].description; // widget.appointmentList[index].description;
widget.dateController.text = widget // widget.dateController.text = widget
.appointmentList[index].date_time // .appointmentList[index].date_time
.split('T')[0]; // .split('T')[0];
widget.timeController.text = widget // widget.timeController.text = widget
.appointmentList[index].date_time // .appointmentList[index].date_time
.split('T')[1] // .split('T')[1]
.substring(0, 5); // .substring(0, 5);
}); // });
Navigator.of(context).pop(); // Navigator.of(context).pop();
}, // },
buttonText: "Cancel", // buttonText: "Cancel",
buttonColor: // buttonColor:
MzanziInnovationHub.of(context)!.theme.errorColor(), // MzanziInnovationHub.of(context)!.theme.errorColor(),
textColor: // textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(), // MzanziInnovationHub.of(context)!.theme.primaryColor(),
), // ),
), // ),
], ],
) )
], ],
@@ -377,8 +508,11 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
void updateAppointmentCall(int index) { void updateAppointmentCall(int index) {
if (isAppointmentInputValid()) { if (isAppointmentInputValid()) {
if (widget.personalSelected == true) {
MihMzansiCalendarApis.updatePersonalAppointment( MihMzansiCalendarApis.updatePersonalAppointment(
widget.signedInUser, widget.signedInUser,
widget.business,
null,
widget.appointmentList[index].idappointments, widget.appointmentList[index].idappointments,
widget.titleController.text, widget.titleController.text,
widget.descriptionIDController.text, widget.descriptionIDController.text,
@@ -386,6 +520,32 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
widget.timeController.text, widget.timeController.text,
context, context,
); );
} else if (widget.personalSelected == false &&
widget.inWaitingRoom == false) {
MihMzansiCalendarApis.updateBusinessAppointment(
widget.signedInUser,
widget.business,
widget.businessUser,
widget.appointmentList[index].idappointments,
widget.titleController.text,
widget.descriptionIDController.text,
widget.dateController.text,
widget.timeController.text,
context,
);
} else {
MihMzansiCalendarApis.updatePatientAppointment(
widget.signedInUser,
widget.business,
widget.businessUser,
widget.appointmentList[index].idappointments,
widget.titleController.text,
widget.descriptionIDController.text,
widget.dateController.text,
widget.timeController.text,
context,
);
}
} else { } else {
showDialog( showDialog(
context: context, context: context,
@@ -397,15 +557,32 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
} }
void deleteAppointmentCall(int index) { void deleteAppointmentCall(int index) {
MihMzansiCalendarApis.deleteLoyaltyCardAPICall( print("personal selected: ${widget.personalSelected}");
MihMzansiCalendarApis.deleteAppointmentAPICall(
widget.signedInUser, widget.signedInUser,
widget.personalSelected,
widget.business,
widget.businessUser,
widget.inWaitingRoom,
widget.appointmentList[index].idappointments, widget.appointmentList[index].idappointments,
context, context,
); );
} }
bool canEditAppointment(int index) { bool canEditAppointment(int index) {
if (widget.appointmentList[index].business_id == "") { if (widget.personalSelected == true &&
widget.appointmentList[index].app_id == widget.signedInUser.app_id &&
widget.appointmentList[index].business_id == "") {
return true;
} else if (widget.personalSelected == false &&
widget.appointmentList[index].business_id ==
widget.business!.business_id &&
widget.appointmentList[index].app_id.isEmpty) {
return true;
} else if (widget.personalSelected == false &&
widget.appointmentList[index].business_id ==
widget.business!.business_id &&
widget.appointmentList[index].app_id.isNotEmpty) {
return true; return true;
} else { } else {
return false; return false;

View File

@@ -69,6 +69,7 @@ class _MzansiCalendarState extends State<MzansiCalendar> {
Appointments( Appointments(
signedInUser: widget.arguments.signedInUser, signedInUser: widget.arguments.signedInUser,
business: widget.arguments.business, business: widget.arguments.business,
businessUser: widget.arguments.businessUser,
personalSelected: widget.arguments.personalSelected, personalSelected: widget.arguments.personalSelected,
), ),
]; ];

View File

@@ -38,6 +38,7 @@ import '../../mih_objects/business_user.dart';
import '../../mih_objects/notification.dart'; import '../../mih_objects/notification.dart';
import '../test/test.dart'; import '../test/test.dart';
// ignore: must_be_immutable
class MIHHome extends StatefulWidget { class MIHHome extends StatefulWidget {
final AppUser signedInUser; final AppUser signedInUser;
final BusinessUser? businessUser; final BusinessUser? businessUser;
@@ -49,8 +50,8 @@ class MIHHome extends StatefulWidget {
final bool isBusinessUser; final bool isBusinessUser;
final bool isBusinessUserNew; final bool isBusinessUserNew;
final bool isDevActive; final bool isDevActive;
final bool personalSelected; bool personalSelected;
const MIHHome({ MIHHome({
super.key, super.key,
required this.signedInUser, required this.signedInUser,
required this.businessUser, required this.businessUser,
@@ -253,6 +254,7 @@ class _MIHHomeState extends State<MIHHome> {
widget.signedInUser, widget.signedInUser,
true, true,
widget.business, widget.business,
null,
), ),
); );
}, },
@@ -363,7 +365,7 @@ class _MIHHomeState extends State<MIHHome> {
), ),
); );
}, },
tileName: "Business Profile", tileName: "Biz Profile",
tileIcon: Center( tileIcon: Center(
child: FaIcon( child: FaIcon(
FontAwesomeIcons.buildingUser, FontAwesomeIcons.buildingUser,
@@ -400,14 +402,15 @@ class _MIHHomeState extends State<MIHHome> {
onTap: () { onTap: () {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
'/patient-manager', '/patient-manager',
arguments: BusinessArguments( arguments: PatManagerArguments(
widget.signedInUser, widget.signedInUser,
widget.businessUser, widget.personalSelected,
widget.business, widget.business,
widget.businessUser,
), ),
); );
}, },
tileName: "Manage Patient", tileName: "Pat Manager",
tileIcon: Center( tileIcon: Center(
child: FaIcon( child: FaIcon(
FontAwesomeIcons.bookMedical, FontAwesomeIcons.bookMedical,
@@ -433,6 +436,7 @@ class _MIHHomeState extends State<MIHHome> {
widget.signedInUser, widget.signedInUser,
false, false,
widget.business, widget.business,
widget.businessUser,
), ),
); );
}, },
@@ -1118,8 +1122,8 @@ class _MIHHomeState extends State<MIHHome> {
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: width / 10, left: width / 13,
right: width / 10, right: width / 13,
bottom: height / 15, bottom: height / 15,
//top: 20, //top: 20,
), ),
@@ -1170,8 +1174,10 @@ class _MIHHomeState extends State<MIHHome> {
text: "Personal", text: "Personal",
onPressed: () { onPressed: () {
setState(() { setState(() {
widget.personalSelected = true;
_selectedIndex = 0; _selectedIndex = 0;
}); });
print("personal selected: ${widget.personalSelected}");
}, },
), ),
GButton( GButton(
@@ -1179,8 +1185,10 @@ class _MIHHomeState extends State<MIHHome> {
text: "Business", text: "Business",
onPressed: () { onPressed: () {
setState(() { setState(() {
widget.personalSelected = false;
_selectedIndex = 1; _selectedIndex = 1;
}); });
print("personal selected: ${widget.personalSelected}");
}, },
), ),
], ],

View File

@@ -135,6 +135,7 @@ class _BuildPatientsListState extends State<BuildPatientAccessList> {
MIHApiCalls.addAppointmentAPICall( MIHApiCalls.addAppointmentAPICall(
widget.arguments.business!.business_id, widget.arguments.business!.business_id,
widget.patientAccesses[index].app_id, widget.patientAccesses[index].app_id,
false,
dateController.text, dateController.text,
timeController.text, timeController.text,
widget.arguments, widget.arguments,

View File

@@ -175,6 +175,7 @@ class _BuildPatientsListState extends State<BuildPatientsList> {
MIHApiCalls.addAppointmentAPICall( MIHApiCalls.addAppointmentAPICall(
widget.arguments.business!.business_id, widget.arguments.business!.business_id,
widget.patients[index].app_id, widget.patients[index].app_id,
false,
dateController.text, dateController.text,
timeController.text, timeController.text,
widget.arguments, widget.arguments,
@@ -523,14 +524,14 @@ class _BuildPatientsListState extends State<BuildPatientsList> {
MzanziInnovationHub.of(context)!.theme.primaryColor(), MzanziInnovationHub.of(context)!.theme.primaryColor(),
onTap: () { onTap: () {
//print("Send access Request..."); //print("Send access Request...");
MIHApiCalls.addPatientAccessAPICall( // MIHApiCalls.addPatientAccessAPICall(
widget.business!.business_id, // widget.business!.business_id,
widget.patients[index].app_id, // widget.patients[index].app_id,
"patient", // "patient",
widget.business!.Name, // widget.business!.Name,
widget.arguments, // widget.arguments,
context, // context,
); // );
}, },
), ),
), ),
@@ -548,12 +549,12 @@ class _BuildPatientsListState extends State<BuildPatientsList> {
MzanziInnovationHub.of(context)!.theme.primaryColor(), MzanziInnovationHub.of(context)!.theme.primaryColor(),
onTap: () { onTap: () {
print("Send rewaply access Request..."); print("Send rewaply access Request...");
MIHApiCalls.reapplyPatientAccessAPICall( // MIHApiCalls.reapplyPatientAccessAPICall(
widget.business!.business_id, // widget.business!.business_id,
widget.patients[index].app_id, // widget.patients[index].app_id,
widget.arguments, // widget.arguments,
context, // context,
); // );
}, },
), ),
), ),

View File

@@ -475,6 +475,7 @@ class _BuildPatientsListState extends State<BuildPatientQueueList> {
MIHApiCalls.deleteApointmentAPICall( MIHApiCalls.deleteApointmentAPICall(
widget.patientQueue[index].idpatient_queue, widget.patientQueue[index].idpatient_queue,
widget.patientQueue[index].app_id, widget.patientQueue[index].app_id,
false,
widget.patientQueue[index].date_time, widget.patientQueue[index].date_time,
BusinessArguments( BusinessArguments(
widget.signedInUser, widget.signedInUser,
@@ -500,6 +501,7 @@ class _BuildPatientsListState extends State<BuildPatientQueueList> {
MIHApiCalls.updateApointmentAPICall( MIHApiCalls.updateApointmentAPICall(
widget.patientQueue[index].idpatient_queue, widget.patientQueue[index].idpatient_queue,
widget.patientQueue[index].app_id, widget.patientQueue[index].app_id,
false,
widget.business!.Name, widget.business!.Name,
widget.patientQueue[index].date_time, widget.patientQueue[index].date_time,
dateController.text, dateController.text,

View File

@@ -0,0 +1,223 @@
import 'package:Mzansi_Innovation_Hub/main.dart';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_api_calls.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_search_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_package/mih-app_tool_body.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import 'package:Mzansi_Innovation_Hub/mih_env/env.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/app_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/patient_access.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/patients.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/pat_manager/list_builders/build_mih_patient_search_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MihPatientSearch extends StatefulWidget {
final AppUser signedInUser;
final Business? business;
final BusinessUser? businessUser;
final bool personalSelected;
const MihPatientSearch({
super.key,
required this.signedInUser,
required this.business,
required this.businessUser,
required this.personalSelected,
});
@override
State<MihPatientSearch> createState() => _MihPatientSearchState();
}
class _MihPatientSearchState extends State<MihPatientSearch> {
TextEditingController _mihPatientSearchController = TextEditingController();
final FocusNode _focusNode = FocusNode();
String _mihPatientSearchString = "";
String baseUrl = AppEnviroment.baseApiUrl;
late Future<List<Patient>> _mihPatientSearchResults;
Widget getPatientSearch() {
return KeyboardListener(
focusNode: _focusNode,
autofocus: true,
onKeyEvent: (event) async {
if (event is KeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.enter) {
// submitPatientForm();
submitPatientSearch();
//To-Do: Implement the search function
// print("To-Do: Implement the search function");
}
},
child: Column(mainAxisSize: MainAxisSize.max, children: [
const Text(
"MIH Patient Lookup",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
//spacer
const SizedBox(height: 10),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
flex: 1,
child: MIHSearchField(
controller: _mihPatientSearchController,
hintText: "ID or Medical Aid No. Search",
required: false,
editable: true,
onTap: () {
// submitPatientForm();
submitPatientSearch();
//To-Do: Implement the search function
// print("To-Do: Implement the search function");
},
),
),
IconButton(
onPressed: () {
setState(() {
_mihPatientSearchController.clear();
_mihPatientSearchString = "";
});
submitPatientSearch();
//To-Do: Implement the search function
// print("To-Do: Implement the search function");
},
icon: const Icon(
Icons.filter_alt_off,
size: 25,
))
],
),
//spacer
const SizedBox(height: 10),
FutureBuilder(
future: _mihPatientSearchResults,
builder: (context, snapshot) {
//print("patient Liust ${snapshot.data}");
if (snapshot.connectionState == ConnectionState.waiting) {
return const Mihloadingcircle();
} else if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
List<Patient> patientsList;
if (_mihPatientSearchString == "") {
patientsList = [];
} else {
patientsList = filterSearchResults(
snapshot.data!, _mihPatientSearchString);
//print(patientsList);
}
return displayPatientList(patientsList, _mihPatientSearchString);
} else {
return Center(
child: Text(
"Error pulling Patients Data\n$baseUrl/patients/search/$_mihPatientSearchString",
style: TextStyle(
fontSize: 25,
color:
MzanziInnovationHub.of(context)!.theme.errorColor()),
textAlign: TextAlign.center,
),
);
}
},
),
]),
);
}
List<Patient> filterSearchResults(List<Patient> patList, String query) {
List<Patient> templist = [];
//print(query);
for (var item in patList) {
if (item.id_no.contains(_mihPatientSearchString) ||
item.medical_aid_no.contains(_mihPatientSearchString)) {
//print(item.medical_aid_no);
templist.add(item);
}
}
return templist;
}
Widget displayPatientList(List<Patient> patientsList, String searchString) {
if (patientsList.isNotEmpty) {
return BuildMihPatientSearchList(
patients: patientsList,
signedInUser: widget.signedInUser,
business: widget.business,
businessUser: widget.businessUser,
personalSelected: widget.personalSelected,
);
} else if (patientsList.isEmpty && searchString != "") {
return Padding(
padding: const EdgeInsets.only(top: 35.0),
child: Center(
child: Text(
"No ID or Medical Aid No. matches a Patient",
style: TextStyle(
fontSize: 25,
color:
MzanziInnovationHub.of(context)!.theme.messageTextColor()),
textAlign: TextAlign.center,
),
),
);
} else {
return Padding(
padding: const EdgeInsets.only(top: 35.0),
child: Center(
child: Text(
"Enter ID or Medical Aid No. of Patient",
style: TextStyle(
fontSize: 25,
color:
MzanziInnovationHub.of(context)!.theme.messageTextColor()),
textAlign: TextAlign.center,
),
),
);
}
}
void submitPatientSearch() {
if (_mihPatientSearchController.text != "") {
setState(() {
_mihPatientSearchString = _mihPatientSearchController.text;
_mihPatientSearchResults =
MIHApiCalls.fetchPatients(_mihPatientSearchString);
});
}
}
//Patient Access Widgets/ Functions
List<PatientAccess> filterAccessResults(
List<PatientAccess> patAccList, String query) {
List<PatientAccess> templist = [];
//print(query);
for (var item in patAccList) {
if (item.id_no.contains(query)) {
//print(item.medical_aid_no);
templist.add(item);
}
}
return templist;
}
@override
void initState() {
super.initState();
_mihPatientSearchResults = MIHApiCalls.fetchPatients("abc");
}
@override
Widget build(BuildContext context) {
return MihAppToolBody(
borderOn: true,
bodyItem: getPatientSearch(),
);
}
}

View File

@@ -0,0 +1,202 @@
import 'package:Mzansi_Innovation_Hub/main.dart';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_api_calls.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_search_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_package/mih-app_tool_body.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import 'package:Mzansi_Innovation_Hub/mih_env/env.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/app_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/patient_access.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/pat_manager/list_builders/build_my_patient_list_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MyPatientList extends StatefulWidget {
final AppUser signedInUser;
final Business? business;
final BusinessUser? businessUser;
final bool personalSelected;
const MyPatientList({
super.key,
required this.signedInUser,
this.business,
this.businessUser,
this.personalSelected = false,
});
@override
State<MyPatientList> createState() => _MyPatientListState();
}
class _MyPatientListState extends State<MyPatientList> {
late Future<List<PatientAccess>> _myPatientList;
TextEditingController _myPatientSearchController = TextEditingController();
String _myPatientIdSearchString = "";
String baseUrl = AppEnviroment.baseApiUrl;
final FocusNode _focusNode = FocusNode();
Widget myPatientListTool() {
return KeyboardListener(
focusNode: _focusNode,
autofocus: true,
onKeyEvent: (event) async {
if (event is KeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.enter) {
setState(() {
_myPatientIdSearchString = _myPatientSearchController.text;
_myPatientList = MIHApiCalls.getPatientAccessListOfBusiness(
widget.business!.business_id);
});
}
},
child: Column(mainAxisSize: MainAxisSize.max, children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"My Patient List",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
IconButton(
iconSize: 20,
icon: const Icon(
Icons.refresh,
),
onPressed: () {
getMyPatientList();
},
),
],
),
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
//spacer
const SizedBox(height: 10),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
flex: 1,
child: MIHSearchField(
controller: _myPatientSearchController,
hintText: "Patient ID Search",
required: false,
editable: true,
onTap: () {
setState(() {
_myPatientIdSearchString = _myPatientSearchController.text;
_myPatientList = MIHApiCalls.getPatientAccessListOfBusiness(
widget.business!.business_id);
});
},
),
),
IconButton(
onPressed: () {
setState(() {
_myPatientSearchController.clear();
_myPatientIdSearchString = "";
});
getMyPatientList();
},
icon: const Icon(
Icons.filter_alt_off,
size: 25,
))
],
),
//spacer
const SizedBox(height: 10),
FutureBuilder(
future: _myPatientList,
builder: (context, snapshot) {
//print("patient Liust ${snapshot.data}");
if (snapshot.connectionState == ConnectionState.waiting) {
return const Mihloadingcircle();
} else if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
List<PatientAccess> patientsAccessList;
if (_myPatientIdSearchString == "") {
patientsAccessList = snapshot.data!;
} else {
patientsAccessList = filterAccessResults(
snapshot.data!, _myPatientIdSearchString);
//print(patientsList);
}
return displayMyPatientList(patientsAccessList);
} else {
return Center(
child: Text(
"Error pulling Patient Access Data\n$baseUrl/access-requests/business/patient/${widget.business!.business_id}",
style: TextStyle(
fontSize: 25,
color:
MzanziInnovationHub.of(context)!.theme.errorColor()),
textAlign: TextAlign.center,
),
);
}
},
),
]),
);
}
Widget displayMyPatientList(List<PatientAccess> patientsAccessList) {
if (patientsAccessList.isNotEmpty) {
return BuildMyPatientListList(
patientAccesses: patientsAccessList,
signedInUser: widget.signedInUser,
business: widget.business,
businessUser: widget.businessUser,
);
}
return Padding(
padding: const EdgeInsets.only(top: 35.0),
child: Center(
child: Text(
"No Patients matching search",
style: TextStyle(
fontSize: 25,
color: MzanziInnovationHub.of(context)!.theme.messageTextColor()),
textAlign: TextAlign.center,
),
),
);
}
List<PatientAccess> filterAccessResults(
List<PatientAccess> patAccList, String query) {
List<PatientAccess> templist = [];
for (var item in patAccList) {
if (item.id_no.contains(query)) {
templist.add(item);
}
}
return templist;
}
void getMyPatientList() {
setState(() {
_myPatientList = MIHApiCalls.getPatientAccessListOfBusiness(
widget.business!.business_id);
});
}
@override
void initState() {
super.initState();
_myPatientList = MIHApiCalls.getPatientAccessListOfBusiness(
widget.business!.business_id);
}
@override
Widget build(BuildContext context) {
return MihAppToolBody(
borderOn: true,
bodyItem: myPatientListTool(),
);
}
}

View File

@@ -0,0 +1,423 @@
import 'package:Mzansi_Innovation_Hub/main.dart';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_mzansi_calendar_apis.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_calendar.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_button.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_date_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_multiline_text_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_time_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_layout/mih_window.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_package/mih-app_tool_body.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_error_message.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import 'package:Mzansi_Innovation_Hub/mih_env/env.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/app_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/appointment.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/calendar/builder/build_appointment_list.dart';
import 'package:flutter/material.dart';
class WaitingRoom extends StatefulWidget {
final AppUser signedInUser;
final Business? business;
final BusinessUser? businessUser;
final bool personalSelected;
final Function(int) onIndexChange;
const WaitingRoom({
super.key,
required this.signedInUser,
required this.business,
required this.businessUser,
required this.personalSelected,
required this.onIndexChange,
});
@override
State<WaitingRoom> createState() => _WaitingRoomState();
}
class _WaitingRoomState extends State<WaitingRoom> {
TextEditingController selectedAppointmentDateController =
TextEditingController();
final TextEditingController _appointmentTitleController =
TextEditingController();
final TextEditingController _appointmentDescriptionIDController =
TextEditingController();
final TextEditingController _appointmentDateController =
TextEditingController();
final TextEditingController _appointmentTimeController =
TextEditingController();
final TextEditingController _patientController = TextEditingController();
String baseUrl = AppEnviroment.baseApiUrl;
String selectedDay = DateTime.now().toString().split(" ")[0];
late Future<List<Appointment>> businessAppointmentResults;
late Future<List<Appointment>> appointmentResults;
bool inWaitingRoom = true;
// Business Appointment Tool
Widget getBusinessAppointmentsTool() {
return Stack(
children: [
Column(
children: [
const Text(
"Waiting Room",
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 25,
),
),
MIHCalendar(
calendarWidth: 500,
rowHeight: 35,
setDate: (value) {
setState(() {
selectedDay = value;
selectedAppointmentDateController.text = selectedDay;
});
}),
// Divider(
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
// ),
Row(
mainAxisSize: MainAxisSize.max,
children: [
FutureBuilder(
future: appointmentResults,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Expanded(
child: Center(child: Mihloadingcircle()));
} else if (snapshot.connectionState ==
ConnectionState.done &&
snapshot.hasData) {
return
// Container(child: const Placeholder());
displayAppointmentList(snapshot.requireData);
} else {
return Center(
child: Text(
"Error pulling appointments",
style: TextStyle(
fontSize: 25,
color: MzanziInnovationHub.of(context)!
.theme
.errorColor()),
textAlign: TextAlign.center,
),
);
}
}),
],
)
],
),
Positioned(
right: 0,
bottom: 0,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
child: IconButton(
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
onPressed: () {
appointmentTypeSelection();
},
icon: const Icon(
Icons.add,
size: 50,
),
),
))
],
);
}
Widget displayAppointmentList(List<Appointment> appointmentList) {
if (appointmentList.isNotEmpty) {
return Expanded(
child: BuildAppointmentList(
appointmentList: appointmentList,
signedInUser: widget.signedInUser,
business: widget.business,
businessUser: widget.businessUser,
personalSelected: widget.personalSelected,
inWaitingRoom: true,
titleController: _appointmentTitleController,
descriptionIDController: _appointmentDescriptionIDController,
patientIdController: _patientController,
dateController: _appointmentDateController,
timeController: _appointmentTimeController,
),
);
}
return Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 35.0),
child: Align(
alignment: Alignment.center,
child: Text(
"No Appointments for $selectedDay",
style: TextStyle(
fontSize: 25,
color: MzanziInnovationHub.of(context)!.theme.messageTextColor(),
),
textAlign: TextAlign.center,
softWrap: true,
),
),
),
);
}
void appointmentTypeSelection() {
String question = "What type of appointment would you like to add?";
question +=
"\n\nExisting Patient: Add an appointment for an patient your practice has access to.";
question +=
"\nExisting MIH User: Add an appointment for an existing MIH user your practice does not have access to.";
question +=
"\nSkeleton Appointment: Add an appointment without a patient linked.";
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return MIHWindow(
fullscreen: false,
windowTitle: "Appointment Type",
windowTools: [],
onWindowTapClose: () {
Navigator.of(context).pop();
},
windowBody: [
Text(
question,
style: TextStyle(
fontSize: 20,
color:
MzanziInnovationHub.of(context)!.theme.secondaryColor()),
textAlign: TextAlign.left,
),
const SizedBox(height: 15),
SizedBox(
width: 500,
height: 50,
child: MIHButton(
onTap: () {
widget.onIndexChange(1);
Navigator.of(context).pop();
},
buttonText: "Existing Patient",
buttonColor:
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(),
),
),
const SizedBox(height: 10),
SizedBox(
width: 500,
height: 50,
child: MIHButton(
onTap: () {
widget.onIndexChange(2);
Navigator.of(context).pop();
},
buttonText: "Existing MIH User",
buttonColor:
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(),
),
),
const SizedBox(height: 10),
SizedBox(
width: 500,
height: 50,
child: MIHButton(
onTap: () {
addAppointmentWindow();
},
buttonText: "Skeleton Appointment",
buttonColor:
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(),
),
),
],
);
},
);
}
void addAppointmentWindow() {
print(widget.personalSelected);
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return MIHWindow(
fullscreen: false,
windowTitle: "Add Appointment",
windowTools: [],
onWindowTapClose: () {
Navigator.of(context).pop();
_appointmentDateController.clear();
_appointmentTimeController.clear();
_appointmentTitleController.clear();
_appointmentDescriptionIDController.clear();
_patientController.clear();
},
windowBody: [
SizedBox(
// width: 500,
child: MIHTextField(
controller: _appointmentTitleController,
hintText: "Title",
editable: true,
required: true,
),
),
const SizedBox(height: 10),
SizedBox(
// width: 500,
child: MIHDateField(
controller: _appointmentDateController,
lableText: "Date",
required: true,
),
),
const SizedBox(height: 10),
SizedBox(
// width: 500,
child: MIHTimeField(
controller: _appointmentTimeController,
lableText: "Time",
required: true,
),
),
const SizedBox(height: 10),
SizedBox(
// width: 500,
height: 250,
child: MIHMLTextField(
controller: _appointmentDescriptionIDController,
hintText: "Description",
editable: true,
required: true,
),
),
const SizedBox(height: 20),
SizedBox(
width: 500,
height: 50,
child: MIHButton(
onTap: () {
addAppointmentCall();
},
buttonText: "Add",
buttonColor:
MzanziInnovationHub.of(context)!.theme.successColor(),
textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(),
),
),
],
);
},
);
}
void addAppointmentCall() {
if (isAppointmentInputValid()) {
if (widget.personalSelected == false) {
MihMzansiCalendarApis.addBusinessAppointment(
widget.signedInUser,
widget.business!,
widget.businessUser!,
true,
_appointmentTitleController.text,
_appointmentDescriptionIDController.text,
_appointmentDateController.text,
_appointmentTimeController.text,
context,
);
} else {
MihMzansiCalendarApis.addPersonalAppointment(
widget.signedInUser,
_appointmentTitleController.text,
_appointmentDescriptionIDController.text,
_appointmentDateController.text,
_appointmentTimeController.text,
context,
);
}
} else {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Input Error");
},
);
}
checkforchange();
}
bool isAppointmentInputValid() {
if (_appointmentTitleController.text.isEmpty ||
_appointmentDescriptionIDController.text.isEmpty ||
_appointmentDateController.text.isEmpty ||
_appointmentTimeController.text.isEmpty) {
return false;
} else {
return true;
}
}
void checkforchange() {
setState(() {
appointmentResults = MihMzansiCalendarApis.getBusinessAppointments(
widget.business!.business_id,
true,
selectedDay,
);
});
}
@override
void dispose() {
selectedAppointmentDateController.dispose();
_appointmentDateController.dispose();
_appointmentTimeController.dispose();
_appointmentTitleController.dispose();
_appointmentDescriptionIDController.dispose();
super.dispose();
}
@override
void initState() {
selectedAppointmentDateController.addListener(checkforchange);
setState(() {
appointmentResults = MihMzansiCalendarApis.getBusinessAppointments(
widget.business!.business_id,
true,
selectedDay,
);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return MihAppToolBody(
borderOn: true,
bodyItem: getBusinessAppointmentsTool(),
);
}
}

View File

@@ -0,0 +1,665 @@
import 'dart:convert';
import 'package:Mzansi_Innovation_Hub/main.dart';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_api_calls.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_button.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_date_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_time_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_layout/mih_window.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_error_message.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_success_message.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_warning_message.dart';
import 'package:Mzansi_Innovation_Hub/mih_env/env.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/app_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/arguments.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/patients.dart';
import 'package:flutter/material.dart';
import 'package:supertokens_flutter/http.dart' as http;
class BuildMihPatientSearchList extends StatefulWidget {
final List<Patient> patients;
final AppUser signedInUser;
final Business? business;
final BusinessUser? businessUser;
final bool personalSelected;
const BuildMihPatientSearchList({
super.key,
required this.patients,
required this.signedInUser,
required this.business,
required this.businessUser,
required this.personalSelected,
});
@override
State<BuildMihPatientSearchList> createState() => _BuildPatientsListState();
}
class _BuildPatientsListState extends State<BuildMihPatientSearchList> {
TextEditingController dateController = TextEditingController();
TextEditingController timeController = TextEditingController();
TextEditingController idController = TextEditingController();
TextEditingController fnameController = TextEditingController();
TextEditingController lnameController = TextEditingController();
TextEditingController accessStatusController = TextEditingController();
final baseAPI = AppEnviroment.baseApiUrl;
Future<void> addPatientAccessAPICall(int index) async {
var response = await http.post(
Uri.parse("$baseAPI/access-requests/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"business_id": widget.business!.business_id,
"app_id": widget.patients[index].app_id,
"date": dateController.text,
"time": timeController.text,
"access": "pending",
}),
);
if (response.statusCode == 201) {
// Navigator.pushNamed(context, '/patient-manager/patient',
// arguments: widget.signedInUser);
String message =
"The appointment has been successfully booked!\n\nAn approval request as been sent to the patient.Once the access request has been approved, you will be able to access the patients profile. ou can check the status of your request in patient queue under the appointment.";
// "${fnameController.text} ${lnameController.text} patient profiole has been successfully added!\n";
Navigator.pop(context);
Navigator.pop(context);
setState(() {
dateController.text = "";
timeController.text = "";
});
Navigator.of(context).pushNamed(
'/patient-manager',
arguments: BusinessArguments(
widget.signedInUser,
widget.businessUser,
widget.business,
),
);
successPopUp(message);
addAccessReviewNotificationAPICall(index);
} else {
internetConnectionPopUp();
}
}
Future<void> addAccessReviewNotificationAPICall(int index) async {
var response = await http.post(
Uri.parse("$baseAPI/notifications/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": widget.patients[index].app_id,
"notification_type": "New Appointment Booked",
"notification_message":
"A new Appointment has been booked by ${widget.business!.Name} for the ${dateController.text} ${timeController.text}. Please approve the Access Review request.",
"action_path": "/access-review",
}),
);
if (response.statusCode == 201) {
// Navigator.pushNamed(context, '/patient-manager/patient',
// arguments: widget.signedInUser);
} else {
internetConnectionPopUp();
}
}
void internetConnectionPopUp() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Internet Connection");
},
);
}
void successPopUp(String message) {
showDialog(
context: context,
builder: (context) {
return MIHSuccessMessage(
successType: "Success",
successMessage: message,
);
},
);
}
void submitApointment(int index) {
//To-Do: Implement the appointment submission
print("To-do: Implement the appointment submission");
// MIHApiCalls.addAppointmentAPICall(
// widget.business!.business_id,
// widget.patients[index].app_id,
// dateController.text,
// timeController.text,
// widget.arguments,
// context,
// );
}
bool isAppointmentFieldsFilled() {
if (dateController.text.isEmpty || timeController.text.isEmpty) {
return false;
} else {
return true;
}
}
void appointmentPopUp(int index) {
var firstLetterFName = widget.patients[index].first_name[0];
var firstLetterLName = widget.patients[index].last_name[0];
var fnameStar = '*' * 8;
var lnameStar = '*' * 8;
setState(() {
idController.text = widget.patients[index].id_no;
fnameController.text = firstLetterFName + fnameStar;
lnameController.text = firstLetterLName + lnameStar;
});
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => MIHWindow(
fullscreen: false,
windowTitle: "Patient Appointment",
windowTools: const [],
onWindowTapClose: () {
Navigator.pop(context);
},
windowBody: [
MIHTextField(
controller: idController,
hintText: "ID No.",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: fnameController,
hintText: "First Name",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: lnameController,
hintText: "Surname",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHDateField(
controller: dateController,
lableText: "Date",
required: true,
),
const SizedBox(height: 10.0),
MIHTimeField(
controller: timeController,
lableText: "Time",
required: true,
),
const SizedBox(height: 30.0),
SizedBox(
width: 300,
height: 50,
child: MIHButton(
buttonText: "Book",
buttonColor:
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
onTap: () {
//print("here1");
bool filled = isAppointmentFieldsFilled();
//print("fields filled: $filled");
if (filled) {
//print("here2");
submitApointment(index);
//print("here3");
} else {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Input Error");
},
);
}
},
),
)
],
),
);
}
void noAccessWarning() {
showDialog(
context: context,
builder: (context) {
return const MIHWarningMessage(warningType: "No Access");
},
);
}
Future<bool> hasAccessToProfile(int index) async {
var hasAccess = false;
await MIHApiCalls.checkBusinessAccessToPatient(
widget.business!.business_id, widget.patients[index].app_id)
.then((results) {
if (results.isEmpty) {
setState(() {
hasAccess = false;
});
} else if (results[0].status == "approved") {
setState(() {
hasAccess = true;
});
} else {
setState(() {
hasAccess = false;
});
}
});
return hasAccess;
}
Future<String> getAccessStatusOfProfile(int index) async {
var accessStatus = "";
await MIHApiCalls.checkBusinessAccessToPatient(
widget.business!.business_id, widget.patients[index].app_id)
.then((results) {
if (results.isEmpty) {
setState(() {
accessStatus = "";
});
} else {
setState(() {
accessStatus = results[0].status;
});
}
});
return accessStatus;
}
void patientProfileChoicePopUp(int index) async {
var hasAccess = false;
String accessStatus = "";
await hasAccessToProfile(index).then((result) {
setState(() {
hasAccess = result;
});
});
await getAccessStatusOfProfile(index).then((result) {
setState(() {
accessStatus = result;
});
});
// print(accessStatus);
// print(hasAccess);
var firstLetterFName = widget.patients[index].first_name[0];
var firstLetterLName = widget.patients[index].last_name[0];
var fnameStar = '*' * 8;
var lnameStar = '*' * 8;
if (accessStatus == "") {
accessStatus = "No Access";
}
setState(() {
idController.text = widget.patients[index].id_no;
fnameController.text = firstLetterFName + fnameStar;
lnameController.text = firstLetterLName + lnameStar;
accessStatusController.text = accessStatus.toUpperCase();
});
//print(accessStatus);
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => MIHWindow(
fullscreen: false,
windowTitle: "Patient Profile",
windowTools: const [],
onWindowTapClose: () {
Navigator.pop(context);
},
windowBody: [
MIHTextField(
controller: idController,
hintText: "ID No.",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: fnameController,
hintText: "First Name",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: lnameController,
hintText: "Surname",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: accessStatusController,
hintText: "Access Status",
editable: false,
required: true,
),
const SizedBox(height: 20.0),
Visibility(
visible: !hasAccess,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Important Notice: Requesting Patient Profile Access",
style: TextStyle(
fontWeight: FontWeight.bold,
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
),
),
Text(
"You are about to request access to a patient's profile. Please be aware of the following important points:",
style: TextStyle(
fontWeight: FontWeight.normal,
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
),
),
SizedBox(
width: 600,
child: Text(
"1. Permanent Access: Once the patient accepts your access request, it will become permanent.",
style: TextStyle(
fontWeight: FontWeight.normal,
color:
MzanziInnovationHub.of(context)!.theme.errorColor(),
),
),
),
SizedBox(
width: 600,
child: Text(
"2. Shared Information: Any updates you make to the patient's profile will be visible to others who have access to the profile.",
style: TextStyle(
fontWeight: FontWeight.normal,
color:
MzanziInnovationHub.of(context)!.theme.errorColor(),
),
),
),
SizedBox(
width: 600,
child: Text(
"3. Irreversible Access: Once granted, you cannot revoke your access to the patient's profile.",
style: TextStyle(
fontWeight: FontWeight.normal,
color:
MzanziInnovationHub.of(context)!.theme.errorColor(),
),
),
),
Text(
"By pressing the \"Request Access\" button you accept the above terms.\n",
style: TextStyle(
fontWeight: FontWeight.bold,
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
),
),
],
),
),
// const SizedBox(height: 15.0),
Wrap(runSpacing: 10, spacing: 10, children: [
// Visibility(
// visible: hasAccess,
// child: SizedBox(
// width: 300,
// height: 50,
// child: MIHButton(
// buttonText: "Book Appointment",
// buttonColor:
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
// textColor:
// MzanziInnovationHub.of(context)!.theme.primaryColor(),
// onTap: () {
// if (hasAccess) {
// appointmentPopUp(index);
// } else {
// noAccessWarning();
// }
// },
// ),
// ),
// ),
Visibility(
visible: hasAccess,
child: SizedBox(
width: 300,
height: 50,
child: MIHButton(
buttonText: "View Patient Profile",
buttonColor:
MzanziInnovationHub.of(context)!.theme.successColor(),
textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(),
onTap: () {
if (hasAccess) {
Navigator.of(context)
.pushNamed('/patient-manager/patient',
arguments: PatientViewArguments(
widget.signedInUser,
widget.patients[index],
widget.businessUser,
widget.business,
"business",
));
} else {
noAccessWarning();
}
},
),
),
),
Visibility(
visible: !hasAccess && accessStatus == "No Access",
child: SizedBox(
width: 300,
height: 50,
child: MIHButton(
buttonText: "Request Access",
buttonColor:
MzanziInnovationHub.of(context)!.theme.successColor(),
textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(),
onTap: () {
//print("Send access Request...");
MIHApiCalls.addPatientAccessAPICall(
widget.business!.business_id,
widget.patients[index].app_id,
"patient",
widget.business!.Name,
widget.personalSelected,
BusinessArguments(
widget.signedInUser,
widget.businessUser,
widget.business,
),
context,
);
},
),
),
),
Visibility(
visible: !hasAccess && accessStatus == "declined",
child: SizedBox(
width: 300,
height: 50,
child: MIHButton(
buttonText: "Re-apply",
buttonColor:
MzanziInnovationHub.of(context)!.theme.successColor(),
textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(),
onTap: () {
// print("Send rewaply access Request...");
MIHApiCalls.reapplyPatientAccessAPICall(
widget.business!.business_id,
widget.patients[index].app_id,
widget.personalSelected,
BusinessArguments(
widget.signedInUser,
widget.businessUser,
widget.business,
),
context,
);
},
),
),
),
Visibility(
visible: !hasAccess && accessStatus == "pending",
child: const SizedBox(
width: 500,
//height: 50,
child: Text(
"Patient has not approved access to their profile. Once access has been approved you can book and appointment or view their profile."),
),
),
])
],
),
);
}
Widget isMainMember(int index) {
//var matchRE = RegExp(r'^[a-z]+$');
var firstLetterFName = widget.patients[index].first_name[0];
var firstLetterLName = widget.patients[index].last_name[0];
var fnameStar = '*' * 8;
var lnameStar = '*' * 8;
if (widget.patients[index].medical_aid_main_member == "Yes") {
return Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
"$firstLetterFName$fnameStar $firstLetterLName$lnameStar",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
const SizedBox(
width: 10,
),
Icon(
Icons.star_border_rounded,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
],
);
} else {
return Text(
"$firstLetterFName$fnameStar $firstLetterLName$lnameStar",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
);
}
}
Widget hasMedicalAid(int index) {
var medAidNoStar = '*' * 8;
if (widget.patients[index].medical_aid == "Yes") {
return ListTile(
title: isMainMember(index),
subtitle: Text(
"ID No.: ${widget.patients[index].id_no}\nMedical Aid No.: $medAidNoStar",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
onTap: () {
patientProfileChoicePopUp(index);
// setState(() {
// appointmentPopUp(index);
// // Add popup to add patienmt to queue
// // Navigator.of(context).pushNamed('/patient-manager/patient',
// // arguments: PatientViewArguments(
// // widget.signedInUser, widget.patients[index], "business"));
// });
},
trailing: Icon(
Icons.arrow_forward,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
);
} else {
return ListTile(
title: isMainMember(index),
subtitle: Text(
"ID No.: ${widget.patients[index].id_no}\nMedical Aid No.: $medAidNoStar",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
onTap: () {
patientProfileChoicePopUp(index);
// setState(() {
// appointmentPopUp(index);
// // Navigator.of(context).pushNamed('/patient-manager/patient',
// // arguments: PatientViewArguments(
// // widget.signedInUser, widget.patients[index], "business"));
// });
},
trailing: Icon(
Icons.add,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
);
}
}
@override
void dispose() {
dateController.dispose();
timeController.dispose();
idController.dispose();
fnameController.dispose();
lnameController.dispose();
accessStatusController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
separatorBuilder: (BuildContext context, index) {
return Divider(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
);
},
itemCount: widget.patients.length,
itemBuilder: (context, index) {
//final patient = widget.patients[index].id_no.contains(widget.searchString);
//print(index);
return hasMedicalAid(index);
},
);
}
}

View File

@@ -0,0 +1,385 @@
import 'package:Mzansi_Innovation_Hub/main.dart';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_api_calls.dart';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_mzansi_calendar_apis.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_button.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_date_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_time_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_layout/mih_window.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_error_message.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_warning_message.dart';
import 'package:Mzansi_Innovation_Hub/mih_env/env.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/app_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/arguments.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/patient_access.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/patients.dart';
import 'package:flutter/material.dart';
class BuildMyPatientListList extends StatefulWidget {
final List<PatientAccess> patientAccesses;
final AppUser signedInUser;
final Business? business;
final BusinessUser? businessUser;
const BuildMyPatientListList({
super.key,
required this.patientAccesses,
required this.signedInUser,
required this.business,
required this.businessUser,
});
@override
State<BuildMyPatientListList> createState() => _BuildPatientsListState();
}
class _BuildPatientsListState extends State<BuildMyPatientListList> {
TextEditingController dateController = TextEditingController();
TextEditingController timeController = TextEditingController();
TextEditingController idController = TextEditingController();
TextEditingController fnameController = TextEditingController();
TextEditingController lnameController = TextEditingController();
final baseAPI = AppEnviroment.baseApiUrl;
void submitApointment(int index) {
//To-Do: Add the appointment to the database
// print("To-Do: Add the appointment to the database");
String description =
"Date: ${dateController.text}\nTime: ${timeController.text}\n";
description += "Medical Practice: ${widget.business!.Name}\n";
description += "Contact Number: ${widget.business!.contact_no}";
MihMzansiCalendarApis.addPatientAppointment(
widget.signedInUser,
false,
widget.patientAccesses[index].app_id,
BusinessArguments(
widget.signedInUser,
widget.businessUser,
widget.business,
),
"${widget.patientAccesses[index].fname} ${widget.patientAccesses[index].lname} - Doctors Visit",
description,
dateController.text,
timeController.text,
context,
);
// MIHApiCalls.addAppointmentAPICall(
// widget.business!.business_id,
// widget.patientAccesses[index].app_id,
// dateController.text,
// timeController.text,
// BusinessArguments(
// widget.signedInUser,
// widget.businessUser,
// widget.business,
// ),
// context,
// );
}
bool isAppointmentFieldsFilled() {
if (dateController.text.isEmpty || timeController.text.isEmpty) {
return false;
} else {
return true;
}
}
void appointmentPopUp(int index) {
var firstLetterFName = widget.patientAccesses[index].fname;
var firstLetterLName = widget.patientAccesses[index].lname;
setState(() {
idController.text = widget.patientAccesses[index].id_no;
fnameController.text = firstLetterFName;
lnameController.text = firstLetterLName;
});
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => MIHWindow(
fullscreen: false,
windowTitle: "Patient Appointment",
windowTools: const [],
onWindowTapClose: () {
Navigator.pop(context);
},
windowBody: [
MIHTextField(
controller: idController,
hintText: "ID No.",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: fnameController,
hintText: "First Name",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: lnameController,
hintText: "Surname",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHDateField(
controller: dateController,
lableText: "Date",
required: true,
),
const SizedBox(height: 10.0),
MIHTimeField(
controller: timeController,
lableText: "Time",
required: true,
),
const SizedBox(height: 30.0),
SizedBox(
width: 300,
height: 50,
child: MIHButton(
buttonText: "Book",
buttonColor:
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
onTap: () {
//print("here1");
bool filled = isAppointmentFieldsFilled();
//print("fields filled: $filled");
if (filled) {
//print("here2");
submitApointment(index);
//print("here3");
} else {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Input Error");
},
);
}
},
),
)
],
),
);
}
void noAccessWarning(int index) {
if (widget.patientAccesses[index].status == "pending") {
showDialog(
context: context,
builder: (context) {
return const MIHWarningMessage(warningType: "No Access");
},
);
} else {
showDialog(
context: context,
builder: (context) {
return const MIHWarningMessage(warningType: "Access Declined");
},
);
}
}
bool hasAccessToProfile(int index) {
var hasAccess = false;
if (widget.patientAccesses[index].status == "approved") {
hasAccess = true;
} else {
hasAccess = false;
}
return hasAccess;
}
void patientProfileChoicePopUp(int index, Patient? patientProfile) async {
var firstLetterFName = widget.patientAccesses[index].fname;
var firstLetterLName = widget.patientAccesses[index].lname;
setState(() {
idController.text = widget.patientAccesses[index].id_no;
fnameController.text = firstLetterFName;
lnameController.text = firstLetterLName;
});
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => MIHWindow(
fullscreen: false,
windowTitle: "Patient Profile",
windowTools: const [],
onWindowTapClose: () {
Navigator.pop(context);
},
windowBody: [
MIHTextField(
controller: idController,
hintText: "ID No.",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: fnameController,
hintText: "First Name",
editable: false,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: lnameController,
hintText: "Surname",
editable: false,
required: true,
),
const SizedBox(height: 30.0),
Wrap(runSpacing: 10, spacing: 10, children: [
SizedBox(
width: 300,
height: 50,
child: MIHButton(
buttonText: "Book Appointment",
buttonColor:
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(),
onTap: () {
appointmentPopUp(index);
},
),
),
SizedBox(
width: 300,
height: 50,
child: MIHButton(
buttonText: "View Patient Profile",
buttonColor:
MzanziInnovationHub.of(context)!.theme.successColor(),
textColor:
MzanziInnovationHub.of(context)!.theme.primaryColor(),
onTap: () {
// Navigator.of(context).pop();
Navigator.of(context).pushNamed('/patient-manager/patient',
arguments: PatientViewArguments(
widget.signedInUser,
patientProfile,
widget.businessUser,
widget.business,
"business",
));
},
),
),
])
],
),
);
}
Widget displayMyPatientTile(int index) {
var firstName = "";
var lastName = "";
String access = widget.patientAccesses[index].status.toUpperCase();
TextSpan accessWithColour;
var hasAccess = false;
hasAccess = hasAccessToProfile(index);
//print(hasAccess);
if (access == "APPROVED") {
firstName = widget.patientAccesses[index].fname;
lastName = widget.patientAccesses[index].lname;
accessWithColour = TextSpan(
text: "$access\n",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.successColor()));
} else if (access == "PENDING") {
firstName = "${widget.patientAccesses[index].fname[0]}********";
lastName = "${widget.patientAccesses[index].lname[0]}********";
accessWithColour = TextSpan(
text: "$access\n",
style: TextStyle(
color:
MzanziInnovationHub.of(context)!.theme.messageTextColor()));
} else {
firstName = "${widget.patientAccesses[index].fname[0]}********";
lastName = "${widget.patientAccesses[index].lname[0]}********";
accessWithColour = TextSpan(
text: "$access\n",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.errorColor()));
}
return ListTile(
title: Text(
"$firstName $lastName",
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
subtitle: RichText(
text: TextSpan(
text: "ID No.: ${widget.patientAccesses[index].id_no}\n",
style: DefaultTextStyle.of(context).style,
children: <TextSpan>[
const TextSpan(text: "Access: "),
accessWithColour,
]),
),
onTap: () async {
Patient? p;
if (hasAccess) {
await MIHApiCalls.fetchPatientByAppId(
widget.patientAccesses[index].app_id)
.then((result) {
setState(() {
p = result;
});
});
patientProfileChoicePopUp(index, p);
} else {
noAccessWarning(index);
}
},
trailing: Icon(
Icons.arrow_forward,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
);
}
@override
void dispose() {
dateController.dispose();
timeController.dispose();
idController.dispose();
fnameController.dispose();
lnameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
separatorBuilder: (BuildContext context, index) {
return Divider(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
);
},
itemCount: widget.patientAccesses.length,
itemBuilder: (context, index) {
return displayMyPatientTile(index);
},
);
}
}

View File

@@ -0,0 +1,15 @@
import 'package:flutter/material.dart';
class BuildWaitingRoomList extends StatefulWidget {
const BuildWaitingRoomList({super.key});
@override
State<BuildWaitingRoomList> createState() => _BuildWaitingRoomListState();
}
class _BuildWaitingRoomListState extends State<BuildWaitingRoomList> {
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

View File

@@ -0,0 +1,110 @@
import 'package:Mzansi_Innovation_Hub/mih_components/mih_package/mih_app.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_package/mih_app_action.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_package/mih_app_tools.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/arguments.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/pat_manager/app_tools/mih_patient_search.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/pat_manager/app_tools/my_patient_list.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/pat_manager/app_tools/waiting_room.dart';
import 'package:flutter/material.dart';
class PatManager extends StatefulWidget {
final PatManagerArguments arguments;
const PatManager({
super.key,
required this.arguments,
});
@override
State<PatManager> createState() => _PatManagerState();
}
class _PatManagerState extends State<PatManager> {
int _selcetedIndex = 0;
void updateIndex(int index) {
setState(() {
_selcetedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return MihApp(
appActionButton: getActionButton(),
appTools: getTools(),
appBody: getToolBody(),
selectedbodyIndex: _selcetedIndex,
onIndexChange: (newValue) {
setState(() {
_selcetedIndex = newValue;
});
print("Index: $_selcetedIndex");
},
);
}
MihAppAction getActionButton() {
return MihAppAction(
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
Navigator.of(context).pop();
},
);
}
MihAppTools getTools() {
Map<Widget, void Function()?> temp = {};
temp[const Icon(Icons.calendar_month)] = () {
setState(() {
_selcetedIndex = 0;
});
};
temp[const Icon(Icons.check_box_outlined)] = () {
setState(() {
_selcetedIndex = 1;
});
};
temp[const Icon(Icons.search)] = () {
setState(() {
_selcetedIndex = 2;
});
};
return MihAppTools(
tools: temp,
selcetedIndex: _selcetedIndex,
);
}
List<Widget> getToolBody() {
List<Widget> toolBodies = [
//appointment here
// Appointments(
// signedInUser: widget.arguments.signedInUser,
// business: widget.arguments.business,
// personalSelected: widget.arguments.personalSelected,
// ),
WaitingRoom(
signedInUser: widget.arguments.signedInUser,
business: widget.arguments.business,
businessUser: widget.arguments.businessUser,
personalSelected: widget.arguments.personalSelected,
onIndexChange: updateIndex,
),
MyPatientList(
signedInUser: widget.arguments.signedInUser,
business: widget.arguments.business,
personalSelected: widget.arguments.personalSelected,
),
MihPatientSearch(
signedInUser: widget.arguments.signedInUser,
business: widget.arguments.business,
personalSelected: widget.arguments.personalSelected,
businessUser: widget.arguments.businessUser,
),
];
return toolBodies;
}
}

View File

@@ -73,11 +73,13 @@ class _PatientManagerState extends State<PatientManager> {
Widget displayQueueList(List<PatientQueue> patientQueueList) { Widget displayQueueList(List<PatientQueue> patientQueueList) {
if (patientQueueList.isNotEmpty) { if (patientQueueList.isNotEmpty) {
return BuildPatientQueueList( return Expanded(
child: BuildPatientQueueList(
patientQueue: patientQueueList, patientQueue: patientQueueList,
signedInUser: widget.arguments.signedInUser, signedInUser: widget.arguments.signedInUser,
business: widget.arguments.business, business: widget.arguments.business,
businessUser: widget.arguments.businessUser, businessUser: widget.arguments.businessUser,
),
); );
} }
return Padding( return Padding(
@@ -95,7 +97,12 @@ class _PatientManagerState extends State<PatientManager> {
} }
Widget patientQueue() { Widget patientQueue() {
return Column(mainAxisSize: MainAxisSize.max, children: [ return Container(
child: Stack(
children: [
Column(
mainAxisSize: MainAxisSize.max,
children: [
//const SizedBox(height: 15), //const SizedBox(height: 15),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@@ -115,7 +122,8 @@ class _PatientManagerState extends State<PatientManager> {
), ),
], ],
), ),
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), // Divider(
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
MIHCalendar( MIHCalendar(
calendarWidth: 500, calendarWidth: 500,
rowHeight: 35, rowHeight: 35,
@@ -125,13 +133,17 @@ class _PatientManagerState extends State<PatientManager> {
}); });
}), }),
//spacer //spacer
Row(
mainAxisSize: MainAxisSize.max,
children: [
FutureBuilder( FutureBuilder(
future: patientQueueResults, future: patientQueueResults,
builder: (context, snapshot) { builder: (context, snapshot) {
//print("patient Queue List ${snapshot.hasData}"); //print("patient Queue List ${snapshot.hasData}");
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Mihloadingcircle(); return const Mihloadingcircle();
} else if (snapshot.connectionState == ConnectionState.done) { } else if (snapshot.connectionState ==
ConnectionState.done) {
List<PatientQueue> patientQueueList; List<PatientQueue> patientQueueList;
// if (searchString == "") { // if (searchString == "") {
// patientQueueList = []; // patientQueueList = [];
@@ -148,14 +160,42 @@ class _PatientManagerState extends State<PatientManager> {
"Error pulling Patients Data\n$baseUrl/patients/search/$searchString", "Error pulling Patients Data\n$baseUrl/patients/search/$searchString",
style: TextStyle( style: TextStyle(
fontSize: 25, fontSize: 25,
color: MzanziInnovationHub.of(context)!.theme.errorColor()), color: MzanziInnovationHub.of(context)!
.theme
.errorColor()),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
); );
} }
}, },
), ),
]); ],
),
],
),
Positioned(
right: 0,
bottom: 0,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color:
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
child: IconButton(
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
onPressed: () {
// addAppointmentWindow();
},
icon: const Icon(
Icons.add,
size: 50,
),
),
))
],
),
);
} }
void refreshQueue() { void refreshQueue() {
@@ -259,7 +299,6 @@ class _PatientManagerState extends State<PatientManager> {
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold), style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
), ),
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
//spacer //spacer
const SizedBox(height: 10), const SizedBox(height: 10),
Row( Row(
@@ -309,7 +348,6 @@ class _PatientManagerState extends State<PatientManager> {
filterSearchResults(snapshot.data!, searchString); filterSearchResults(snapshot.data!, searchString);
//print(patientsList); //print(patientsList);
} }
return displayPatientList(patientsList, searchString); return displayPatientList(patientsList, searchString);
} else { } else {
return Center( return Center(
@@ -347,7 +385,6 @@ class _PatientManagerState extends State<PatientManager> {
} }
//Patient Access Widgets/ Functions //Patient Access Widgets/ Functions
List<PatientAccess> filterAccessResults( List<PatientAccess> filterAccessResults(
List<PatientAccess> patAccList, String query) { List<PatientAccess> patAccList, String query) {
List<PatientAccess> templist = []; List<PatientAccess> templist = [];
@@ -414,7 +451,6 @@ class _PatientManagerState extends State<PatientManager> {
], ],
), ),
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()), Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
//spacer //spacer
const SizedBox(height: 10), const SizedBox(height: 10),
Row( Row(
@@ -446,7 +482,6 @@ class _PatientManagerState extends State<PatientManager> {
)) ))
], ],
), ),
//spacer //spacer
const SizedBox(height: 10), const SizedBox(height: 10),
FutureBuilder( FutureBuilder(
@@ -465,7 +500,6 @@ class _PatientManagerState extends State<PatientManager> {
filterAccessResults(snapshot.data!, accessSearchString); filterAccessResults(snapshot.data!, accessSearchString);
//print(patientsList); //print(patientsList);
} }
return displayPatientAccessList(patientsAccessList); return displayPatientAccessList(patientsAccessList);
} else { } else {
return Center( return Center(

View File

@@ -6,6 +6,7 @@ import 'package:Mzansi_Innovation_Hub/mih_packages/mih_policy_tos/mih_terms_of_s
import 'package:Mzansi_Innovation_Hub/mih_packages/mzansi_ai/mzansi_ai.dart'; import 'package:Mzansi_Innovation_Hub/mih_packages/mzansi_ai/mzansi_ai.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/mzansi_wallet/mih_barcode_scanner.dart'; import 'package:Mzansi_Innovation_Hub/mih_packages/mzansi_wallet/mih_barcode_scanner.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/mzansi_wallet/mzansi_wallet.dart'; import 'package:Mzansi_Innovation_Hub/mih_packages/mzansi_wallet/mzansi_wallet.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/pat_manager/pat_manager.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../mih_components/mih_layout/mih_print_prevew.dart'; import '../mih_components/mih_layout/mih_print_prevew.dart';
import '../mih_components/mih_pop_up_messages/mih_notification_message.dart'; import '../mih_components/mih_pop_up_messages/mih_notification_message.dart';
@@ -13,7 +14,7 @@ import '../mih_packages/authentication/auth_check.dart';
import '../mih_packages/patient_profile/add_or_view_patient.dart'; import '../mih_packages/patient_profile/add_or_view_patient.dart';
import '../mih_packages/patient_profile/patient_add.dart'; import '../mih_packages/patient_profile/patient_add.dart';
import '../mih_packages/patient_profile/patient_edit.dart'; import '../mih_packages/patient_profile/patient_edit.dart';
import '../mih_packages/patient_profile/patient_manager.dart'; // import '../mih_packages/patient_profile/patient_manager.dart';
import '../mih_objects/app_user.dart'; import '../mih_objects/app_user.dart';
import '../mih_objects/arguments.dart'; import '../mih_objects/arguments.dart';
import '../mih_packages/about_mih/mih_about.dart'; import '../mih_packages/about_mih/mih_about.dart';
@@ -244,13 +245,16 @@ class RouteGenerator {
//Patient Manager Pages //Patient Manager Pages
case '/patient-manager': case '/patient-manager':
if (args is BusinessArguments) { if (args is PatManagerArguments) {
//print("route generator: $args"); //print("route generator: $args");
return MaterialPageRoute( return MaterialPageRoute(
settings: settings, settings: settings,
builder: (_) => PatientManager( builder: (_) => PatManager(
arguments: args, arguments: args,
), ),
// PatientManager(
// arguments: args,
// ),
); );
} }
return _errorRoute(); return _errorRoute();