diff --git a/File_Storage/Mzanzi_Innovation_Hub/.minio.sys/buckets/.tracker.bin b/File_Storage/Mzanzi_Innovation_Hub/.minio.sys/buckets/.tracker.bin index 48967666..df0564fb 100644 Binary files a/File_Storage/Mzanzi_Innovation_Hub/.minio.sys/buckets/.tracker.bin and b/File_Storage/Mzanzi_Innovation_Hub/.minio.sys/buckets/.tracker.bin differ diff --git a/Frontend/patient_manager/lib/components/buildMedList.dart b/Frontend/patient_manager/lib/components/buildMedList.dart new file mode 100644 index 00000000..0fbbe7a5 --- /dev/null +++ b/Frontend/patient_manager/lib/components/buildMedList.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:patient_manager/objects/medicine.dart'; + +class BuildMedicinesList extends StatefulWidget { + final TextEditingController contoller; + final List medicines; + //final searchString; + + const BuildMedicinesList({ + super.key, + required this.contoller, + required this.medicines, + //required this.searchString, + }); + + @override + State createState() => _BuildMedicinesListState(); +} + +int indexOn = 0; + +class _BuildMedicinesListState extends State { + @override + Widget build(BuildContext context) { + return ListView.separated( + separatorBuilder: (BuildContext context, int index) { + return const Divider(); + }, + itemCount: widget.medicines.length, + itemBuilder: (context, index) { + //final patient = widget.patients[index].id_no.contains(widget.searchString); + return ListTile( + title: Text(widget.medicines[index].name), + subtitle: Text( + "${widget.medicines[index].unit} - ${widget.medicines[index].form}"), + onTap: () { + setState(() { + widget.contoller.text = widget.medicines[index].name; + Navigator.of(context).pop(); + }); + }, + trailing: const Icon(Icons.arrow_forward), + ); + }, + ); + } +} diff --git a/Frontend/patient_manager/lib/components/medicineSearch.dart b/Frontend/patient_manager/lib/components/medicineSearch.dart new file mode 100644 index 00000000..c7c01aa2 --- /dev/null +++ b/Frontend/patient_manager/lib/components/medicineSearch.dart @@ -0,0 +1,152 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:patient_manager/components/buildMedList.dart'; +import 'package:patient_manager/components/myErrorMessage.dart'; +import 'package:patient_manager/objects/medicine.dart'; +import 'package:http/http.dart' as http; + +class MedicineSearch extends StatefulWidget { + final TextEditingController searchVlaue; + const MedicineSearch({ + super.key, + required this.searchVlaue, + }); + + @override + State createState() => _MedicineSearchState(); +} + +class _MedicineSearchState extends State { + final String endpointMeds = "http://localhost:80/users/medicine/"; + + //TextEditingController searchController = TextEditingController(); + + late Future> futueMeds; + //String searchString = ""; + + Future> getMedList(String endpoint) async { + final response = await http.get(Uri.parse(endpoint)); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List medicines = + List.from(l.map((model) => Medicine.fromJson(model))); + // List meds = []; + // medicines.forEach((element) => meds.add(element.name)); + return medicines; + } else { + internetConnectionPopUp(); + throw Exception('failed to load medicine'); + } + } + + void internetConnectionPopUp() { + showDialog( + context: context, + builder: (context) { + return const MyErrorMessage(errorType: "Internet Connection"); + }, + ); + } + + @override + void initState() { + futueMeds = getMedList(endpointMeds + widget.searchVlaue.text); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Dialog( + child: Stack( + children: [ + Container( + padding: const EdgeInsets.all(10.0), + width: 700.0, + //height: 475.0, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(25.0), + border: Border.all(color: Colors.blueAccent, width: 5.0), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + "Select Medicine", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.blueAccent, + fontSize: 35.0, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25.0), + // MySearchField( + // controller: searchController, + // hintText: "Medicine", + // onChanged: (value) { + // setState(() { + // searchString = value; + // }); + // }, + // required: true, + // editable: true, + // onTap: () {}, + // ), + FutureBuilder( + future: futueMeds, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const SizedBox( + height: 400, + child: const Center( + child: CircularProgressIndicator(), + ), + ); + } else if (snapshot.hasData) { + final medsList = snapshot.data!; + return SizedBox( + height: 400, + child: BuildMedicinesList( + contoller: widget.searchVlaue, + medicines: medsList, + //searchString: searchString, + ), + ); + } else { + return const SizedBox( + height: 400, + child: const Center( + child: Text("Error Loading Medicines"), + ), + ); + } + }, + ), + ], + ), + ), + Positioned( + top: 5, + right: 5, + width: 50, + height: 50, + child: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon( + Icons.close, + color: Colors.red, + size: 35, + ), + ), + ), + ], + ), + ); + } +} diff --git a/Frontend/patient_manager/lib/components/myDropdownInput.dart b/Frontend/patient_manager/lib/components/myDropdownInput.dart index 573ea237..9c8cc1b6 100644 --- a/Frontend/patient_manager/lib/components/myDropdownInput.dart +++ b/Frontend/patient_manager/lib/components/myDropdownInput.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:patient_manager/objects/appUser.dart'; class MyDropdownField extends StatefulWidget { final TextEditingController controller; - final AppUser signedInUser; final String hintText; final bool required; final List dropdownOptions; @@ -13,7 +11,6 @@ class MyDropdownField extends StatefulWidget { const MyDropdownField({ super.key, required this.controller, - required this.signedInUser, required this.hintText, required this.dropdownOptions, required this.required, @@ -92,6 +89,7 @@ class _MyDropdownFieldState extends State { return Padding( padding: const EdgeInsets.symmetric(horizontal: 25.0), child: DropdownMenu( + menuHeight: 300, controller: widget.controller, expandedInsets: EdgeInsets.zero, label: setRequiredText(), diff --git a/Frontend/patient_manager/lib/components/mySearchInput.dart b/Frontend/patient_manager/lib/components/mySearchInput.dart index 6e7a19cc..b1e9ba1b 100644 --- a/Frontend/patient_manager/lib/components/mySearchInput.dart +++ b/Frontend/patient_manager/lib/components/mySearchInput.dart @@ -1,36 +1,113 @@ import 'package:flutter/material.dart'; -class MySearchField extends StatelessWidget { - final controller; +class MySearchField extends StatefulWidget { + final TextEditingController controller; final String hintText; + final bool required; + final bool editable; final void Function(String)? onChanged; + final void Function() onTap; const MySearchField({ super.key, required this.controller, required this.hintText, required this.onChanged, + required this.required, + required this.editable, + required this.onTap, }); + @override + State createState() => _MySearchFieldState(); +} + +class _MySearchFieldState extends State { + bool startup = true; + FocusNode _focus = FocusNode(); + + bool makeEditable() { + if (widget.editable) { + return false; + } else { + return true; + } + } + + String? get _errorText { + final text = widget.controller.text; + if (startup) { + return null; + } + if (!widget.required) { + return null; + } + if (text.isEmpty) { + return "${widget.hintText} is required"; + } + return null; + } + + void _onFocusChange() { + setState(() { + startup = false; + }); + } + + Widget setRequiredText() { + if (widget.required) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + "*", + style: TextStyle(color: Colors.red), + ), + const SizedBox( + width: 8.0, + ), + Text(widget.hintText, + style: const TextStyle(color: Colors.blueAccent)), + ], + ); + } else { + return Text(widget.hintText, + style: const TextStyle(color: Colors.blueAccent)); + } + } + + @override + void initState() { + _focus.addListener(_onFocusChange); + super.initState(); + } + @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 25.0), child: TextField( - onChanged: onChanged, - controller: controller, + onChanged: widget.onChanged, + controller: widget.controller, + readOnly: makeEditable(), + focusNode: _focus, obscureText: false, decoration: InputDecoration( fillColor: Colors.white, - prefixIcon: const Icon( - Icons.search, - color: Colors.blueAccent, + prefixIcon: IconButton( + icon: const Icon( + Icons.search, + color: Colors.blueAccent, + ), + onPressed: () { + if (widget.controller.text != "") { + widget.onTap(); + } + }, ), filled: true, - label: Text(hintText), - labelStyle: const TextStyle(color: Colors.blueAccent), - //hintText: hintText, - //hintStyle: TextStyle(color: Colors.blueGrey[400]), + label: setRequiredText(), + errorText: _errorText, enabledBorder: const OutlineInputBorder( borderSide: BorderSide( color: Colors.blueAccent, diff --git a/Frontend/patient_manager/lib/components/patientFiles.dart b/Frontend/patient_manager/lib/components/patientFiles.dart index 312fd37d..0c0d3ea3 100644 --- a/Frontend/patient_manager/lib/components/patientFiles.dart +++ b/Frontend/patient_manager/lib/components/patientFiles.dart @@ -9,6 +9,7 @@ import 'package:patient_manager/components/myErrorMessage.dart'; import 'package:patient_manager/components/mySuccessMessage.dart'; import 'package:patient_manager/components/myTextInput.dart'; import 'package:patient_manager/components/mybutton.dart'; +import 'package:patient_manager/components/prescipInput.dart'; import 'package:patient_manager/main.dart'; import 'package:patient_manager/objects/appUser.dart'; import 'package:patient_manager/objects/files.dart'; @@ -41,6 +42,13 @@ class _PatientFilesState extends State { final endDateTextController = TextEditingController(); final retDateTextController = TextEditingController(); final selectedFileController = TextEditingController(); + final medicineController = TextEditingController(); + final quantityController = TextEditingController(); + final dosageController = TextEditingController(); + final timesDailyController = TextEditingController(); + final noDaysController = TextEditingController(); + final noRepeatsController = TextEditingController(); + final outputController = TextEditingController(); late Future> futueFiles; late String userEmail = ""; @@ -301,6 +309,70 @@ class _PatientFilesState extends State { ); } + void prescritionPopUp() { + showDialog( + context: context, + builder: (context) => Dialog( + child: Stack( + children: [ + Container( + padding: const EdgeInsets.all(10.0), + width: 900.0, + //height: 475.0, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(25.0), + border: Border.all(color: Colors.blueAccent, width: 5.0), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + "Create Precrition", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.blueAccent, + fontSize: 35.0, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25.0), + PrescripInput( + medicineController: medicineController, + quantityController: quantityController, + dosageController: dosageController, + timesDailyController: timesDailyController, + noDaysController: noDaysController, + noRepeatsController: noRepeatsController, + outputController: outputController, + ), + ], + ), + ), + Positioned( + top: 5, + right: 5, + width: 50, + height: 50, + child: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon( + Icons.close, + color: Colors.red, + size: 35, + ), + ), + ), + ], + ), + ), + ); + } + void uploudFilePopUp() { showDialog( context: context, @@ -486,7 +558,9 @@ class _PatientFilesState extends State { icon: const Icon(Icons.sick_outlined), ), IconButton( - onPressed: () {}, + onPressed: () { + prescritionPopUp(); + }, icon: const Icon(Icons.medication_outlined), ), IconButton( diff --git a/Frontend/patient_manager/lib/components/prescipInput.dart b/Frontend/patient_manager/lib/components/prescipInput.dart new file mode 100644 index 00000000..7d535f12 --- /dev/null +++ b/Frontend/patient_manager/lib/components/prescipInput.dart @@ -0,0 +1,216 @@ +import 'package:flutter/material.dart'; +import 'package:patient_manager/components/medicineSearch.dart'; +import 'package:patient_manager/components/myDropdownInput.dart'; +import 'package:patient_manager/components/myMLTextInput.dart'; +import 'package:patient_manager/components/mySearchInput.dart'; +import 'package:patient_manager/components/mybutton.dart'; + +class PrescripInput extends StatefulWidget { + final TextEditingController medicineController; + final TextEditingController quantityController; + final TextEditingController dosageController; + final TextEditingController timesDailyController; + final TextEditingController noDaysController; + final TextEditingController noRepeatsController; + final TextEditingController outputController; + + const PrescripInput({ + super.key, + required this.medicineController, + required this.quantityController, + required this.dosageController, + required this.timesDailyController, + required this.noDaysController, + required this.noRepeatsController, + required this.outputController, + }); + + @override + State createState() => _PrescripInputState(); +} + +class _PrescripInputState extends State { + String searchString = ""; + + final numberOptions = [ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30" + ]; + + void getMedsPopUp(TextEditingController medSearch) { + showDialog( + context: context, + builder: (context) { + return MedicineSearch( + searchVlaue: medSearch, + ); + }, + ); + } + + @override + void initState() { + //futueMeds = getMedList(endpointMeds); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + children: [ + SizedBox( + width: 300, + child: MySearchField( + controller: widget.medicineController, + hintText: "Medicine", + onChanged: (value) { + setState(() { + searchString = value; + }); + }, + required: true, + editable: true, + onTap: () { + getMedsPopUp(widget.medicineController); + }, + ), + ), + const SizedBox(height: 25.0), + SizedBox( + width: 300, + child: MyDropdownField( + controller: widget.quantityController, + hintText: "Quantity", + dropdownOptions: numberOptions, + required: true, + ), + ), + const SizedBox(height: 25.0), + SizedBox( + width: 300, + child: MyDropdownField( + controller: widget.dosageController, + hintText: "Dosage", + dropdownOptions: numberOptions, + required: true, + ), + ), + const SizedBox(height: 25.0), + SizedBox( + width: 300, + child: MyDropdownField( + controller: widget.timesDailyController, + hintText: "Times Daily", + dropdownOptions: numberOptions, + required: true, + ), + ), + const SizedBox(height: 25.0), + SizedBox( + width: 300, + child: MyDropdownField( + controller: widget.noDaysController, + hintText: "No. Days", + dropdownOptions: numberOptions, + required: true, + ), + ), + const SizedBox(height: 25.0), + SizedBox( + width: 300, + child: MyDropdownField( + controller: widget.noRepeatsController, + hintText: "No. Repeats", + dropdownOptions: numberOptions, + required: true, + ), + ), + SizedBox( + width: 300, + child: MyButton( + onTap: () {}, + buttonText: "Add", + buttonColor: Colors.blueAccent, + textColor: Colors.white, + ), + ) + ], + ), + //const SizedBox(height: 50.0), + Column( + children: [ + SizedBox( + width: 550, + height: 400, + child: MyMLTextField( + controller: widget.outputController, + hintText: "Prescrion Output", + editable: false, + required: false, + ), + ), + SizedBox( + width: 300, + height: 100, + child: MyButton( + onTap: () { + // if (isMedCertFieldsFilled()) { + // generateMedCert(); + // Navigator.pop(context); + // } else { + // showDialog( + // context: context, + // builder: (context) { + // return const MyErrorMessage( + // errorType: "Input Error"); + // }, + // ); + // } + }, + buttonText: "Generate", + buttonColor: Colors.green, + textColor: Colors.white, + ), + ) + ], + ), + ], + ), + ); + } +} diff --git a/Frontend/patient_manager/lib/components/profileUserUpdate.dart b/Frontend/patient_manager/lib/components/profileUserUpdate.dart index 9312bbc6..a51d975f 100644 --- a/Frontend/patient_manager/lib/components/profileUserUpdate.dart +++ b/Frontend/patient_manager/lib/components/profileUserUpdate.dart @@ -69,7 +69,6 @@ class _ProfileUserUpdateState extends State { const SizedBox(height: 10.0), MyDropdownField( controller: titleController, - signedInUser: widget.signedInUser, hintText: "Title", dropdownOptions: const ["Dr.", "Assistant"], required: true, diff --git a/Frontend/patient_manager/lib/objects/medicine.dart b/Frontend/patient_manager/lib/objects/medicine.dart new file mode 100644 index 00000000..489fd6c4 --- /dev/null +++ b/Frontend/patient_manager/lib/objects/medicine.dart @@ -0,0 +1,19 @@ +class Medicine { + final String name; + final String unit; + final String form; + + const Medicine( + this.name, + this.unit, + this.form, + ); + + factory Medicine.fromJson(dynamic json) { + return Medicine( + json['name'], + json['unit'], + json['dosage form'], + ); + } +} diff --git a/Frontend/patient_manager/lib/pages/patientManager.dart b/Frontend/patient_manager/lib/pages/patientManager.dart index feb5a0f1..63258d64 100644 --- a/Frontend/patient_manager/lib/pages/patientManager.dart +++ b/Frontend/patient_manager/lib/pages/patientManager.dart @@ -88,6 +88,9 @@ class _PatientManagerState extends State { MySearchField( controller: searchController, hintText: "ID Search", + required: false, + editable: true, + onTap: () {}, onChanged: (value) { setState(() { searchString = value; diff --git a/database/#ib_16384_0.dblwr b/database/#ib_16384_0.dblwr index d1723c4c..eb4a249c 100644 Binary files a/database/#ib_16384_0.dblwr and b/database/#ib_16384_0.dblwr differ diff --git a/database/#innodb_redo/#ib_redo18 b/database/#innodb_redo/#ib_redo18 index 664d4ff7..a922d98a 100644 Binary files a/database/#innodb_redo/#ib_redo18 and b/database/#innodb_redo/#ib_redo18 differ diff --git a/database/#innodb_temp/temp_1.ibt b/database/#innodb_temp/temp_1.ibt index 04af030d..0fdc5904 100644 Binary files a/database/#innodb_temp/temp_1.ibt and b/database/#innodb_temp/temp_1.ibt differ diff --git a/database/#innodb_temp/temp_10.ibt b/database/#innodb_temp/temp_10.ibt index 61d85459..3fbba9dd 100644 Binary files a/database/#innodb_temp/temp_10.ibt and b/database/#innodb_temp/temp_10.ibt differ diff --git a/database/#innodb_temp/temp_2.ibt b/database/#innodb_temp/temp_2.ibt index 9231eb4f..527f7ee7 100644 Binary files a/database/#innodb_temp/temp_2.ibt and b/database/#innodb_temp/temp_2.ibt differ diff --git a/database/#innodb_temp/temp_3.ibt b/database/#innodb_temp/temp_3.ibt index 524ac5af..3610fd68 100644 Binary files a/database/#innodb_temp/temp_3.ibt and b/database/#innodb_temp/temp_3.ibt differ diff --git a/database/#innodb_temp/temp_4.ibt b/database/#innodb_temp/temp_4.ibt index c200f807..dc0b6bc1 100644 Binary files a/database/#innodb_temp/temp_4.ibt and b/database/#innodb_temp/temp_4.ibt differ diff --git a/database/#innodb_temp/temp_5.ibt b/database/#innodb_temp/temp_5.ibt index a0b9b95f..c425e14a 100644 Binary files a/database/#innodb_temp/temp_5.ibt and b/database/#innodb_temp/temp_5.ibt differ diff --git a/database/#innodb_temp/temp_6.ibt b/database/#innodb_temp/temp_6.ibt index 082454e1..88968703 100644 Binary files a/database/#innodb_temp/temp_6.ibt and b/database/#innodb_temp/temp_6.ibt differ diff --git a/database/#innodb_temp/temp_7.ibt b/database/#innodb_temp/temp_7.ibt index ad8ed386..8a55d1e4 100644 Binary files a/database/#innodb_temp/temp_7.ibt and b/database/#innodb_temp/temp_7.ibt differ diff --git a/database/#innodb_temp/temp_8.ibt b/database/#innodb_temp/temp_8.ibt index 42a7560b..8236c1e5 100644 Binary files a/database/#innodb_temp/temp_8.ibt and b/database/#innodb_temp/temp_8.ibt differ diff --git a/database/#innodb_temp/temp_9.ibt b/database/#innodb_temp/temp_9.ibt index a952e495..98f9ef3b 100644 Binary files a/database/#innodb_temp/temp_9.ibt and b/database/#innodb_temp/temp_9.ibt differ diff --git a/database/binlog.000051 b/database/binlog.000051 index db8a11b7..ad591e56 100644 Binary files a/database/binlog.000051 and b/database/binlog.000051 differ diff --git a/database/binlog.000052 b/database/binlog.000052 new file mode 100644 index 00000000..fd980f3f Binary files /dev/null and b/database/binlog.000052 differ diff --git a/database/binlog.000053 b/database/binlog.000053 new file mode 100644 index 00000000..c1687dca Binary files /dev/null and b/database/binlog.000053 differ diff --git a/database/binlog.000054 b/database/binlog.000054 new file mode 100644 index 00000000..23ae8a70 Binary files /dev/null and b/database/binlog.000054 differ diff --git a/database/binlog.000055 b/database/binlog.000055 new file mode 100644 index 00000000..b36287f6 Binary files /dev/null and b/database/binlog.000055 differ diff --git a/database/binlog.000056 b/database/binlog.000056 new file mode 100644 index 00000000..b2c5bcf4 Binary files /dev/null and b/database/binlog.000056 differ diff --git a/database/ib_buffer_pool b/database/ib_buffer_pool index de85978b..6bf00390 100644 --- a/database/ib_buffer_pool +++ b/database/ib_buffer_pool @@ -1,6 +1,5 @@ -4294967294,449 -4294967278,389 -4294967279,331 +4294967279,321 +4294967278,397 4294967293,131 4294967293,130 4294967293,129 @@ -142,7 +141,6 @@ 4243767282,0 4243767281,0 4294967293,0 -4294967278,323 4294967278,160 4294967278,48 4294967278,322 @@ -271,6 +269,7 @@ 4294967278,428 4294967278,258 4294967278,5 +4294967278,389 4294967278,257 4294967278,4 4294967278,3 @@ -294,3 +293,4 @@ 4294967279,127 4294967279,449 4294967279,442 +4294967279,126 diff --git a/database/ibdata1 b/database/ibdata1 index 8305f029..d5367271 100644 Binary files a/database/ibdata1 and b/database/ibdata1 differ diff --git a/database/ibtmp1 b/database/ibtmp1 index e59d0ed8..7681f528 100644 Binary files a/database/ibtmp1 and b/database/ibtmp1 differ diff --git a/database/mysql.ibd b/database/mysql.ibd index ee03d786..a66c88f1 100644 Binary files a/database/mysql.ibd and b/database/mysql.ibd differ diff --git a/database/undo_001 b/database/undo_001 index 3094c751..fb92627e 100644 Binary files a/database/undo_001 and b/database/undo_001 differ diff --git a/database/undo_002 b/database/undo_002 index e7c1dbd8..134c4e05 100644 Binary files a/database/undo_002 and b/database/undo_002 differ