app files restructure
This commit is contained in:
466
Frontend/lib/mih_packages/about_mih/mih_about.dart
Normal file
466
Frontend/lib/mih_packages/about_mih/mih_about.dart
Normal file
@@ -0,0 +1,466 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_layout/mih_tile.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import "package:universal_html/js.dart" as js;
|
||||
import 'dart:html' as html;
|
||||
|
||||
class MIHAbout extends StatefulWidget {
|
||||
const MIHAbout({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MIHAbout> createState() => _MIHAboutState();
|
||||
}
|
||||
|
||||
class _MIHAboutState extends State<MIHAbout> {
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||
'/',
|
||||
arguments: true,
|
||||
(route) => false,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"About",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: false,
|
||||
bodyItems: [
|
||||
SizedBox(
|
||||
width: 165,
|
||||
child: Image(
|
||||
image: MzanziInnovationHub.of(context)!.theme.altLogoImage()),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const Text(
|
||||
"Mzansi Innovation Hub",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 30,
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: Divider(),
|
||||
),
|
||||
// const SizedBox(
|
||||
// height: 10,
|
||||
// ),
|
||||
Wrap(
|
||||
alignment: WrapAlignment.start,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
children: [
|
||||
ourVision(),
|
||||
ourMission(),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Wrap(
|
||||
alignment: WrapAlignment.start,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
js.context.callMethod("presentAddToHome");
|
||||
},
|
||||
buttonText: "Install MIH",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
html.window.open(
|
||||
'https://www.youtube.com/playlist?list=PLuT35kJIui0H5kXjxNOZlHoOPZbQLr4qh',
|
||||
'new tab');
|
||||
},
|
||||
buttonText: "MIH Beginners Guide",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
]),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: Divider(),
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
// spacing: 10,
|
||||
// runSpacing: 10,
|
||||
children: [
|
||||
founderTitle(),
|
||||
founderBio(),
|
||||
],
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: Divider(),
|
||||
),
|
||||
mihSocials(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget founderBio() {
|
||||
String bio = "";
|
||||
bio += "BSc Comnputer Science & Information Systems\n";
|
||||
bio += "(University of the Western Cap)\n";
|
||||
bio +=
|
||||
"6 Year of banking experience with one of the big 5 banks of South Africa.";
|
||||
ImageProvider logoFrame =
|
||||
MzanziInnovationHub.of(context)!.theme.altLogoFrame();
|
||||
return Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 300,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
fit: StackFit.loose,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
backgroundColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
backgroundImage: const AssetImage("images/founder.jpg"),
|
||||
//'https://media.licdn.com/dms/image/D4D03AQGd1-QhjtWWpA/profile-displayphoto-shrink_400_400/0/1671698053061?e=2147483647&v=beta&t=a3dJI5yxs5-KeXjj10LcNCFuC9IOfa8nNn3k_Qyr0CA'),
|
||||
radius: 75,
|
||||
),
|
||||
SizedBox(
|
||||
width: 165,
|
||||
child: Image(image: logoFrame),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: Text(
|
||||
bio,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
//fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget founderTitle() {
|
||||
String heading = "Yasien Meth (Founder & CEO)";
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
heading,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget ourVision() {
|
||||
String heading = "Our Vision";
|
||||
String vision =
|
||||
"Digitizing Mzansi one process at a time. Discover essential Mzansi apps to streamline your personal and professional life. Simplify your daily tasks with our user-friendly solutions.";
|
||||
|
||||
return SizedBox(
|
||||
width: 500,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Text(
|
||||
heading,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Text(
|
||||
vision,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
//fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget ourMission() {
|
||||
String heading = "Our Mission";
|
||||
String mission =
|
||||
"Bridge the digital divide in Mzansi, ensuring that everyone can benefit from the power of technology. We empower lives by providing simple, elegant solutions that elevate daily experiences. With our user-friendly approach, we're making the digital world accessible to all, ensuring no one is left behind in the digital revolution.";
|
||||
|
||||
return SizedBox(
|
||||
width: 500,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
heading,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Text(
|
||||
mission,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
//fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget mihSocials() {
|
||||
String heading = "Follow Our Journey";
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
heading,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: 500,
|
||||
height: 300,
|
||||
child: GridView.builder(
|
||||
padding: const EdgeInsets.only(
|
||||
// left: width / 10,
|
||||
// right: width / 10,
|
||||
// //bottom: height / 5,
|
||||
// top: 20,
|
||||
),
|
||||
// physics: ,
|
||||
// shrinkWrap: true,
|
||||
itemCount: getSocialsList().length,
|
||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
mainAxisSpacing: 15, maxCrossAxisExtent: 150),
|
||||
itemBuilder: (context, index) {
|
||||
return getSocialsList()[index];
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> getSocialsList() {
|
||||
List<Widget> socials = [];
|
||||
socials.add(MIHTile(
|
||||
onTap: () {
|
||||
html.window
|
||||
.open('https://www.tiktok.com/@mzansi.innovation.hub', 'new tab');
|
||||
},
|
||||
tileName: "TikTok",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.tiktok,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
size: 200,
|
||||
),
|
||||
),
|
||||
p: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
s: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
));
|
||||
//==================================================================
|
||||
socials.add(MIHTile(
|
||||
onTap: () {
|
||||
html.window
|
||||
.open('https://www.instagram.com/mzansi.innovation.hub', 'new tab');
|
||||
},
|
||||
tileName: "Instagram",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.instagram,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
size: 200,
|
||||
),
|
||||
),
|
||||
p: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
s: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
));
|
||||
//==================================================================
|
||||
socials.add(MIHTile(
|
||||
onTap: () {
|
||||
html.window
|
||||
.open('https://www.youtube.com/@mzansiinnovationhub', 'new tab');
|
||||
},
|
||||
tileName: "YouTube",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.youtube,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
size: 175,
|
||||
),
|
||||
),
|
||||
p: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
s: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
));
|
||||
//==================================================================
|
||||
socials.add(MIHTile(
|
||||
onTap: () {
|
||||
html.window.open('https://x.com/mzansi_inno_hub', 'new tab');
|
||||
},
|
||||
tileName: "X",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.xTwitter,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
size: 200,
|
||||
),
|
||||
),
|
||||
p: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
s: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
));
|
||||
//==================================================================
|
||||
socials.add(MIHTile(
|
||||
onTap: () {
|
||||
html.window.open(
|
||||
'https://www.linkedin.com/company/mzansi-innovation-hub/',
|
||||
'new tab');
|
||||
},
|
||||
tileName: "LinkedIn",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.linkedin,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
size: 200,
|
||||
),
|
||||
),
|
||||
p: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
s: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
));
|
||||
//==================================================================
|
||||
socials.add(MIHTile(
|
||||
onTap: () {
|
||||
html.window.open(
|
||||
'https://www.facebook.com/profile.php?id=61565345762136',
|
||||
'new tab');
|
||||
},
|
||||
tileName: "FaceBook",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.facebook,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
size: 200,
|
||||
),
|
||||
),
|
||||
p: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
s: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
));
|
||||
//==================================================================
|
||||
return socials;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
secondaryActionButton: null,
|
||||
header: getHeader(),
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../../mih_components/mih_layout/mih_window.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_warning_message.dart';
|
||||
import '../../../mih_env/env.dart';
|
||||
import '../../../mih_objects/access_request.dart';
|
||||
import '../../../mih_objects/app_user.dart';
|
||||
|
||||
class BuildAccessRequestList extends StatefulWidget {
|
||||
final List<AccessRequest> accessRequests;
|
||||
final AppUser signedInUser;
|
||||
|
||||
const BuildAccessRequestList({
|
||||
super.key,
|
||||
required this.accessRequests,
|
||||
required this.signedInUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildAccessRequestList> createState() => _BuildPatientsListState();
|
||||
}
|
||||
|
||||
class _BuildPatientsListState extends State<BuildAccessRequestList> {
|
||||
String baseAPI = AppEnviroment.baseApiUrl;
|
||||
late double popUpWidth;
|
||||
late double? popUpheight;
|
||||
late double popUpButtonWidth;
|
||||
late double popUpTitleSize;
|
||||
late double popUpSubtitleSize;
|
||||
late double popUpBodySize;
|
||||
late double popUpIconSize;
|
||||
late double popUpPaddingSize;
|
||||
late double width;
|
||||
late double height;
|
||||
|
||||
Future<void> updateAccessAPICall(int index, String accessType) async {
|
||||
var response = await http.put(
|
||||
Uri.parse("$baseAPI/access-requests/update/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": widget.accessRequests[index].business_id,
|
||||
"app_id": widget.accessRequests[index].app_id,
|
||||
"date_time": widget.accessRequests[index].date_time,
|
||||
"access": accessType,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
//Navigator.of(context).pushNamed('/home');
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed(
|
||||
'/patient-access-review',
|
||||
arguments: widget.signedInUser,
|
||||
);
|
||||
String message = "";
|
||||
if (accessType == "approved") {
|
||||
message =
|
||||
"You've successfully approved the access request! ${widget.accessRequests[index].Name} now has access to your profile until ${widget.accessRequests[index].revoke_date.substring(0, 16).replaceAll("T", " ")}.";
|
||||
} else {
|
||||
message =
|
||||
"You've declined the access request. ${widget.accessRequests[index].Name} will not have access to your profile.";
|
||||
}
|
||||
successPopUp(message);
|
||||
} 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 accessCancelledWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "Access Cancelled");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget displayQueue(int index) {
|
||||
String line1 =
|
||||
"Appointment: ${widget.accessRequests[index].date_time.substring(0, 16).replaceAll("T", " ")}";
|
||||
String line2 = "";
|
||||
line2 += "Requestor: ${widget.accessRequests[index].Name}\n";
|
||||
//subtitle += "Business Type: ${widget.accessRequests[index].type}\n";
|
||||
String line3 = "Access: ";
|
||||
String access = "";
|
||||
var nowDate = DateTime.now();
|
||||
var expireyDate = DateTime.parse(widget.accessRequests[index].revoke_date);
|
||||
|
||||
if (expireyDate.isBefore(nowDate)) {
|
||||
access += "EXPIRED";
|
||||
} else {
|
||||
access += "${widget.accessRequests[index].access.toUpperCase()}";
|
||||
}
|
||||
String line4 = "";
|
||||
if (widget.accessRequests[index].revoke_date.contains("9999")) {
|
||||
line4 += "Access Expiration date: NOT SET";
|
||||
} else {
|
||||
line4 +=
|
||||
"Access Expiration date: ${widget.accessRequests[index].revoke_date.substring(0, 10)}";
|
||||
}
|
||||
TextSpan accessWithColour;
|
||||
if (access == "APPROVED") {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.successColor()));
|
||||
} else if (access == "PENDING") {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.messageTextColor()));
|
||||
} else {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor()));
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
title: Text(
|
||||
line1,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
subtitle: RichText(
|
||||
text: TextSpan(
|
||||
text: line2,
|
||||
style: DefaultTextStyle.of(context).style,
|
||||
children: <TextSpan>[
|
||||
TextSpan(text: line3),
|
||||
accessWithColour,
|
||||
TextSpan(text: line4),
|
||||
]),
|
||||
),
|
||||
// Text(
|
||||
// subtitle,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
onTap: () {
|
||||
if (access == "CANCELLED") {
|
||||
accessCancelledWarning();
|
||||
} else {
|
||||
viewApprovalPopUp(index);
|
||||
}
|
||||
},
|
||||
// trailing: Icon(
|
||||
// Icons.arrow_forward,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
);
|
||||
}
|
||||
|
||||
void checkScreenSize() {
|
||||
if (MzanziInnovationHub.of(context)!.theme.screenType == "desktop") {
|
||||
setState(() {
|
||||
popUpWidth = (width / 4) * 2;
|
||||
popUpheight = null;
|
||||
popUpButtonWidth = 300;
|
||||
popUpTitleSize = 25.0;
|
||||
popUpSubtitleSize = 20.0;
|
||||
popUpBodySize = 15;
|
||||
popUpPaddingSize = 25.0;
|
||||
popUpIconSize = 100;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
popUpWidth = width - (width * 0.1);
|
||||
popUpheight = null;
|
||||
popUpButtonWidth = 300;
|
||||
popUpTitleSize = 20.0;
|
||||
popUpSubtitleSize = 18.0;
|
||||
popUpBodySize = 15;
|
||||
popUpPaddingSize = 15.0;
|
||||
popUpIconSize = 100;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void viewApprovalPopUp(int index) {
|
||||
String subtitle =
|
||||
"Appointment: ${widget.accessRequests[index].date_time.substring(0, 16).replaceAll("T", " ")}\n";
|
||||
subtitle += "Requestor: ${widget.accessRequests[index].Name}\n";
|
||||
subtitle += "Business Type: ${widget.accessRequests[index].type}\n\n";
|
||||
subtitle +=
|
||||
"You are about to approve an access request to your patient profile.\nPlease be aware that once approved, ${widget.accessRequests[index].Name} will have access to your profile information until ${widget.accessRequests[index].revoke_date.substring(0, 16).replaceAll("T", " ")}.\nIf you are unsure about an upcoming appointment with ${widget.accessRequests[index].Name}, please contact ${widget.accessRequests[index].contact_no} for clarification before approving this request.\n";
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Update Appointment Access",
|
||||
windowBody: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Text(
|
||||
subtitle,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
fontSize: popUpBodySize,
|
||||
//fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
Wrap(
|
||||
runSpacing: 10,
|
||||
spacing: 10,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: popUpButtonWidth,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
updateAccessAPICall(index, "declined");
|
||||
},
|
||||
buttonText: "Decline",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: popUpButtonWidth,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
updateAccessAPICall(index, "approved");
|
||||
},
|
||||
buttonText: "Approve",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.successColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
windowTools: const [],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
}),
|
||||
);
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => Dialog(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// Container(
|
||||
// //padding: const EdgeInsets.all(15.0),
|
||||
// width: popUpWidth,
|
||||
// height: popUpheight,
|
||||
// decoration: BoxDecoration(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
// borderRadius: BorderRadius.circular(25.0),
|
||||
// border: Border.all(
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// width: 5.0),
|
||||
// ),
|
||||
// child: SingleChildScrollView(
|
||||
// padding: EdgeInsets.all(popUpPaddingSize),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Update Appointment Access",
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// fontSize: popUpTitleSize,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 15.0),
|
||||
// Text(
|
||||
// subtitle,
|
||||
// textAlign: TextAlign.left,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// fontSize: popUpBodySize,
|
||||
// //fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// Wrap(
|
||||
// runSpacing: 10,
|
||||
// spacing: 10,
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// width: popUpButtonWidth,
|
||||
// height: 50,
|
||||
// child: MIHButton(
|
||||
// onTap: () {
|
||||
// updateAccessAPICall(index, "declined");
|
||||
// },
|
||||
// buttonText: "Decline",
|
||||
// buttonColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .errorColor(),
|
||||
// textColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .primaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: popUpButtonWidth,
|
||||
// height: 50,
|
||||
// child: MIHButton(
|
||||
// onTap: () {
|
||||
// updateAccessAPICall(index, "approved");
|
||||
// },
|
||||
// buttonText: "Approve",
|
||||
// buttonColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .successColor(),
|
||||
// textColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .primaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 5,
|
||||
// right: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pop(context);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.close,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var size = MediaQuery.of(context).size;
|
||||
setState(() {
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
});
|
||||
checkScreenSize();
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
separatorBuilder: (BuildContext context, index) {
|
||||
return Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
);
|
||||
},
|
||||
itemCount: widget.accessRequests.length,
|
||||
itemBuilder: (context, index) {
|
||||
//final patient = widget.patients[index].id_no.contains(widget.searchString);
|
||||
//print(index);
|
||||
return displayQueue(index);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,465 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_apis/mih_api_calls.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../../mih_components/mih_layout/mih_window.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_warning_message.dart';
|
||||
import '../../../mih_env/env.dart';
|
||||
import '../../../mih_objects/app_user.dart';
|
||||
import '../../../mih_objects/patient_access.dart';
|
||||
|
||||
class BuildBusinessAccessList extends StatefulWidget {
|
||||
final List<PatientAccess> patientAccessList;
|
||||
final AppUser signedInUser;
|
||||
|
||||
const BuildBusinessAccessList({
|
||||
super.key,
|
||||
required this.patientAccessList,
|
||||
required this.signedInUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildBusinessAccessList> createState() => _BuildPatientsListState();
|
||||
}
|
||||
|
||||
class _BuildPatientsListState extends State<BuildBusinessAccessList> {
|
||||
String baseAPI = AppEnviroment.baseApiUrl;
|
||||
late double popUpWidth;
|
||||
late double? popUpheight;
|
||||
late double popUpButtonWidth;
|
||||
late double popUpTitleSize;
|
||||
late double popUpSubtitleSize;
|
||||
late double popUpBodySize;
|
||||
late double popUpIconSize;
|
||||
late double popUpPaddingSize;
|
||||
late double width;
|
||||
late double height;
|
||||
|
||||
// Future<void> updateAccessAPICall(int index, String accessType) async {
|
||||
// var response = await http.put(
|
||||
// Uri.parse("$baseAPI/access-requests/update/"),
|
||||
// headers: <String, String>{
|
||||
// "Content-Type": "application/json; charset=UTF-8"
|
||||
// },
|
||||
// body: jsonEncode(<String, dynamic>{
|
||||
// "business_id": widget.patientAccessList[index].business_id,
|
||||
// "app_id": widget.patientAccessList[index].app_id,
|
||||
// "date_time": widget.patientAccessList[index].date_time,
|
||||
// "access": accessType,
|
||||
// }),
|
||||
// );
|
||||
// if (response.statusCode == 200) {
|
||||
// //Navigator.of(context).pushNamed('/home');
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pushNamed(
|
||||
// '/patient-access-review',
|
||||
// arguments: widget.signedInUser,
|
||||
// );
|
||||
// String message = "";
|
||||
// if (accessType == "approved") {
|
||||
// message =
|
||||
// "You've successfully approved the access request! ${widget.patientAccessList[index].Name} now has access to your profile until ${widget.patientAccessList[index].revoke_date.substring(0, 16).replaceAll("T", " ")}.";
|
||||
// } else {
|
||||
// message =
|
||||
// "You've declined the access request. ${widget.patientAccessList[index].Name} will not have access to your profile.";
|
||||
// }
|
||||
// successPopUp(message);
|
||||
// } 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 accessCancelledWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "Access Cancelled");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget displayQueue(int index) {
|
||||
String line1 =
|
||||
"Business Name: ${widget.patientAccessList[index].requested_by}";
|
||||
String line2 = "";
|
||||
|
||||
line2 +=
|
||||
"Request Date: ${widget.patientAccessList[index].requested_on.substring(0, 16).replaceAll("T", " ")}\n";
|
||||
line2 +=
|
||||
"Profile Type: ${widget.patientAccessList[index].type.toUpperCase()}\n";
|
||||
//subtitle += "Business Type: ${widget.patientAccessList[index].type}\n";
|
||||
String line3 = "Status: ";
|
||||
String access = widget.patientAccessList[index].status.toUpperCase();
|
||||
|
||||
TextSpan accessWithColour;
|
||||
if (access == "APPROVED") {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.successColor()));
|
||||
} else if (access == "PENDING") {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.messageTextColor()));
|
||||
} else {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor()));
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
title: Text(
|
||||
line1,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
subtitle: RichText(
|
||||
text: TextSpan(
|
||||
text: line2,
|
||||
style: DefaultTextStyle.of(context).style,
|
||||
children: <TextSpan>[
|
||||
TextSpan(text: line3),
|
||||
accessWithColour,
|
||||
]),
|
||||
),
|
||||
// Text(
|
||||
// subtitle,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
onTap: () {
|
||||
viewApprovalPopUp(index);
|
||||
},
|
||||
// trailing: Icon(
|
||||
// Icons.arrow_forward,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
);
|
||||
}
|
||||
|
||||
void checkScreenSize() {
|
||||
if (MzanziInnovationHub.of(context)!.theme.screenType == "desktop") {
|
||||
setState(() {
|
||||
popUpWidth = (width / 4) * 2;
|
||||
popUpheight = null;
|
||||
popUpButtonWidth = 300;
|
||||
popUpTitleSize = 25.0;
|
||||
popUpSubtitleSize = 20.0;
|
||||
popUpBodySize = 15;
|
||||
popUpPaddingSize = 25.0;
|
||||
popUpIconSize = 100;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
popUpWidth = width - (width * 0.1);
|
||||
popUpheight = null;
|
||||
popUpButtonWidth = 300;
|
||||
popUpTitleSize = 20.0;
|
||||
popUpSubtitleSize = 18.0;
|
||||
popUpBodySize = 15;
|
||||
popUpPaddingSize = 15.0;
|
||||
popUpIconSize = 100;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void viewApprovalPopUp(int index) {
|
||||
String subtitle =
|
||||
"Business Name: ${widget.patientAccessList[index].requested_by}\n";
|
||||
subtitle +=
|
||||
"Requested Date: ${widget.patientAccessList[index].requested_on.substring(0, 16).replaceAll("T", " ")}\n";
|
||||
|
||||
subtitle +=
|
||||
"Profile Type: ${widget.patientAccessList[index].type.toUpperCase()}\n";
|
||||
subtitle +=
|
||||
"Status: ${widget.patientAccessList[index].status.toUpperCase()}";
|
||||
if (widget.patientAccessList[index].status == 'pending') {
|
||||
// "\nYou are about to approve an access request to your patient profile.\nPlease be aware that once approved, ${widget.patientAccessList[index].requested_by} will have access to your profile forever and will be able to contribute to it.\nIf you are unsure about an upcoming appointment with ${widget.patientAccessList[index].requested_by}, please contact *Add Number here* for clarification before approving this request.";
|
||||
} else {
|
||||
subtitle +=
|
||||
"\nActioned By: ${widget.patientAccessList[index].approved_by}\n";
|
||||
subtitle +=
|
||||
"Actioned On: ${widget.patientAccessList[index].approved_on.substring(0, 16).replaceAll("T", " ")}";
|
||||
// subtitle +=
|
||||
// "You have approved this access request to your patient profile.\nPlease be aware that once approved, ${widget.patientAccessList[index].requested_by} will have access to your profile forever and will be able to contribute to it.";
|
||||
}
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Profile Access",
|
||||
windowBody: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: 1000,
|
||||
child: Text(
|
||||
subtitle,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
fontSize: popUpBodySize,
|
||||
//fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
Visibility(
|
||||
visible: widget.patientAccessList[index].status == 'pending',
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Important Notice: Approving Profile Access",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"You are about to accept access to your patient's profile. Please be aware of the following important points:",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 700,
|
||||
child: Text(
|
||||
"1. Permanent Access: Once you accepts this access request, it will become permanent.",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 700,
|
||||
child: Text(
|
||||
"2. Shared Information: Any updates make to youe patient profile will be visible to all who have access to the profile.",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 700,
|
||||
child: Text(
|
||||
"3. Irreversible Access: Once granted, you cannot revoke access to your patient's profile.",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"By pressing the \"Approve\" button you accept the above terms.",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: widget.patientAccessList[index].status == 'approved',
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Important Notice: Approved Profile Access",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"You have accepted access to your patient's profile. Please be aware of the following important points:",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 700,
|
||||
child: Text(
|
||||
"1. Permanent Access: This access is permanent.",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 700,
|
||||
child: Text(
|
||||
"2. Shared Information: Any updates make to youe patient profile will be visible to all who have access to the profile.",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 700,
|
||||
child: Text(
|
||||
"3. Irreversible Access: You cannot revoke this access to your patient's profile.",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Visibility(
|
||||
visible: widget.patientAccessList[index].status == 'pending',
|
||||
child: Wrap(
|
||||
runSpacing: 10,
|
||||
spacing: 10,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: popUpButtonWidth,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
print("request declined");
|
||||
MIHApiCalls.updatePatientAccessAPICall(
|
||||
widget.patientAccessList[index].business_id,
|
||||
widget.patientAccessList[index].requested_by,
|
||||
widget.patientAccessList[index].app_id,
|
||||
"declined",
|
||||
"${widget.signedInUser.fname} ${widget.signedInUser.lname}",
|
||||
widget.signedInUser,
|
||||
context,
|
||||
);
|
||||
//updateAccessAPICall(index, "declined");
|
||||
},
|
||||
buttonText: "Decline",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: popUpButtonWidth,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
print("request approved");
|
||||
MIHApiCalls.updatePatientAccessAPICall(
|
||||
widget.patientAccessList[index].business_id,
|
||||
widget.patientAccessList[index].requested_by,
|
||||
widget.patientAccessList[index].app_id,
|
||||
"approved",
|
||||
"${widget.signedInUser.fname} ${widget.signedInUser.lname}",
|
||||
widget.signedInUser,
|
||||
context,
|
||||
);
|
||||
//updateAccessAPICall(index, "approved");
|
||||
},
|
||||
buttonText: "Approve",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.successColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
windowTools: const [],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var size = MediaQuery.of(context).size;
|
||||
setState(() {
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
});
|
||||
checkScreenSize();
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
separatorBuilder: (BuildContext context, index) {
|
||||
return Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
);
|
||||
},
|
||||
itemCount: widget.patientAccessList.length,
|
||||
itemBuilder: (context, index) {
|
||||
//final patient = widget.patients[index].id_no.contains(widget.searchString);
|
||||
//print(index);
|
||||
return displayQueue(index);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../main.dart';
|
||||
import '../../mih_apis/mih_api_calls.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/patient_access.dart';
|
||||
import 'builder/build_business_access_list.dart';
|
||||
|
||||
class PatientAccessRequest extends StatefulWidget {
|
||||
final AppUser signedInUser;
|
||||
|
||||
const PatientAccessRequest({
|
||||
super.key,
|
||||
required this.signedInUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PatientAccessRequest> createState() => _PatientAccessRequestState();
|
||||
}
|
||||
|
||||
class _PatientAccessRequestState extends State<PatientAccessRequest> {
|
||||
TextEditingController filterController = TextEditingController();
|
||||
|
||||
String baseUrl = AppEnviroment.baseApiUrl;
|
||||
|
||||
String errorCode = "";
|
||||
String errorBody = "";
|
||||
String datefilter = "";
|
||||
String accessFilter = "";
|
||||
bool forceRefresh = false;
|
||||
late String selectedDropdown;
|
||||
|
||||
late Future<List<PatientAccess>> accessList;
|
||||
|
||||
// Future<List<AccessRequest>> fetchAccessRequests() async {
|
||||
// //print("Patien manager page: $endpoint");
|
||||
// final response = await http.get(
|
||||
// Uri.parse("$baseUrl/access-requests/${widget.signedInUser.app_id}"));
|
||||
// // print("Here");
|
||||
// // print("Body: ${response.body}");
|
||||
// // print("Code: ${response.statusCode}");
|
||||
// errorCode = response.statusCode.toString();
|
||||
// errorBody = response.body;
|
||||
|
||||
// if (response.statusCode == 200) {
|
||||
// //print("Here1");
|
||||
// Iterable l = jsonDecode(response.body);
|
||||
// //print("Here2");
|
||||
// List<AccessRequest> patientQueue = List<AccessRequest>.from(
|
||||
// l.map((model) => AccessRequest.fromJson(model)));
|
||||
// //print("Here3");
|
||||
// //print(patientQueue);
|
||||
// return patientQueue;
|
||||
// } else {
|
||||
// throw Exception('failed to load patients');
|
||||
// }
|
||||
// }
|
||||
|
||||
List<PatientAccess> filterSearchResults(List<PatientAccess> accessList) {
|
||||
List<PatientAccess> templist = [];
|
||||
|
||||
for (var item in accessList) {
|
||||
if (filterController.text == "All") {
|
||||
templist.add(item);
|
||||
} else {
|
||||
if (item.status.contains(filterController.text.toLowerCase())) {
|
||||
templist.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return templist;
|
||||
}
|
||||
|
||||
void refreshList() {
|
||||
if (forceRefresh == true) {
|
||||
setState(() {
|
||||
accessList = MIHApiCalls.getBusinessAccessListOfPatient(
|
||||
widget.signedInUser.app_id);
|
||||
forceRefresh = false;
|
||||
});
|
||||
} else if (selectedDropdown != filterController.text) {
|
||||
setState(() {
|
||||
accessList = MIHApiCalls.getBusinessAccessListOfPatient(
|
||||
widget.signedInUser.app_id);
|
||||
selectedDropdown = filterController.text;
|
||||
});
|
||||
}
|
||||
// setState(() {
|
||||
// accessRequestResults = fetchAccessRequests();
|
||||
// });
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
Navigator.of(context).popAndPushNamed(
|
||||
'/',
|
||||
arguments: true,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"Forever Access List",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: true,
|
||||
bodyItems: [
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Flexible(
|
||||
child: MIHDropdownField(
|
||||
controller: filterController,
|
||||
hintText: "Access Types",
|
||||
dropdownOptions: const [
|
||||
"All",
|
||||
"Approved",
|
||||
"Pending",
|
||||
"Declined",
|
||||
"Cancelled"
|
||||
],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
forceRefresh = true;
|
||||
});
|
||||
refreshList();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.refresh,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder(
|
||||
future: accessList,
|
||||
builder: (context, snapshot) {
|
||||
//print("patient Queue List ${snapshot.hasData}");
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Mihloadingcircle();
|
||||
} else if (snapshot.connectionState == ConnectionState.done) {
|
||||
List<PatientAccess> accessRequestList;
|
||||
accessRequestList = filterSearchResults(snapshot.requireData);
|
||||
if (accessRequestList.isNotEmpty) {
|
||||
return BuildBusinessAccessList(
|
||||
signedInUser: widget.signedInUser,
|
||||
patientAccessList: accessRequestList,
|
||||
);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"No Request have been made.",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.messageTextColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// return Expanded(
|
||||
// child: displayAccessRequestList(accessRequestList),
|
||||
// );
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"$errorCode: Error pulling Patients Data\n$baseUrl/queue/patients/\n$errorBody",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
filterController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
selectedDropdown = "All";
|
||||
filterController.text = "All";
|
||||
filterController.addListener(refreshList);
|
||||
setState(() {
|
||||
accessList = MIHApiCalls.getBusinessAccessListOfPatient(
|
||||
widget.signedInUser.app_id);
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
}
|
||||
}
|
||||
380
Frontend/lib/mih_packages/appointment/appointments.dart
Normal file
380
Frontend/lib/mih_packages/appointment/appointments.dart
Normal file
@@ -0,0 +1,380 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_apis/mih_api_calls.dart';
|
||||
import '../../mih_components/mih_calendar.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/access_request.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/patient_queue.dart';
|
||||
import '../access_review/builder/build_access_request_list.dart';
|
||||
import 'builder/build_appointment_list.dart';
|
||||
|
||||
class Appointments extends StatefulWidget {
|
||||
final AppUser signedInUser;
|
||||
|
||||
const Appointments({
|
||||
super.key,
|
||||
required this.signedInUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<Appointments> createState() => _PatientAccessRequestState();
|
||||
}
|
||||
|
||||
class _PatientAccessRequestState extends State<Appointments> {
|
||||
TextEditingController filterController = TextEditingController();
|
||||
TextEditingController appointmentDateController = TextEditingController();
|
||||
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];
|
||||
|
||||
late Future<List<AccessRequest>> accessRequestResults;
|
||||
late Future<List<PatientQueue>> personalQueueResults;
|
||||
|
||||
Future<List<AccessRequest>> fetchAccessRequests() async {
|
||||
//print("Patien manager page: $endpoint");
|
||||
final response = await http.get(
|
||||
Uri.parse("$baseUrl/access-requests/${widget.signedInUser.app_id}"));
|
||||
// print("Here");
|
||||
// print("Body: ${response.body}");
|
||||
// print("Code: ${response.statusCode}");
|
||||
errorCode = response.statusCode.toString();
|
||||
errorBody = response.body;
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
//print("Here1");
|
||||
Iterable l = jsonDecode(response.body);
|
||||
//print("Here2");
|
||||
List<AccessRequest> patientQueue = List<AccessRequest>.from(
|
||||
l.map((model) => AccessRequest.fromJson(model)));
|
||||
//print("Here3");
|
||||
//print(patientQueue);
|
||||
return patientQueue;
|
||||
} else {
|
||||
throw Exception('failed to load patients');
|
||||
}
|
||||
}
|
||||
|
||||
List<AccessRequest> filterSearchResults(List<AccessRequest> accessList) {
|
||||
List<AccessRequest> templist = [];
|
||||
|
||||
for (var item in accessList) {
|
||||
if (filterController.text == "All") {
|
||||
if (item.date_time.contains(datefilter)) {
|
||||
templist.add(item);
|
||||
}
|
||||
} else {
|
||||
if (item.date_time.contains(datefilter) &&
|
||||
item.access.contains(filterController.text.toLowerCase())) {
|
||||
templist.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return templist;
|
||||
}
|
||||
|
||||
Widget displayAccessRequestList(List<AccessRequest> accessRequestList) {
|
||||
if (accessRequestList.isNotEmpty) {
|
||||
return BuildAccessRequestList(
|
||||
signedInUser: widget.signedInUser,
|
||||
accessRequests: accessRequestList,
|
||||
|
||||
// BuildPatientQueueList(
|
||||
// patientQueue: patientQueueList,
|
||||
// signedInUser: widget.signedInUser,
|
||||
// ),
|
||||
);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"No Request have been made.",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!.theme.messageTextColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget viewAccessRequest(double w, double h) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: SizedBox(
|
||||
width: w,
|
||||
height: h,
|
||||
child: Column(mainAxisSize: MainAxisSize.max, children: [
|
||||
//const SizedBox(height: 15),
|
||||
const Text(
|
||||
"Access Request",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
SizedBox(
|
||||
width: 500,
|
||||
child: MIHDropdownField(
|
||||
controller: filterController,
|
||||
hintText: "Access Types",
|
||||
dropdownOptions: const ["All", "Approved", "Pending", "Declined"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder(
|
||||
future: accessRequestResults,
|
||||
builder: (context, snapshot) {
|
||||
//print("patient Queue List ${snapshot.hasData}");
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Expanded(
|
||||
child: Container(
|
||||
//height: 500,
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
border: Border.all(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
width: 3.0),
|
||||
),
|
||||
child: const Mihloadingcircle(),
|
||||
),
|
||||
);
|
||||
} else if (snapshot.connectionState == ConnectionState.done) {
|
||||
List<AccessRequest> accessRequestList;
|
||||
accessRequestList = filterSearchResults(snapshot.requireData);
|
||||
if (accessRequestList.isNotEmpty) {
|
||||
return BuildAccessRequestList(
|
||||
signedInUser: widget.signedInUser,
|
||||
accessRequests: accessRequestList,
|
||||
);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"No Request have been made.",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.messageTextColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// return Expanded(
|
||||
// child: displayAccessRequestList(accessRequestList),
|
||||
// );
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"$errorCode: Error pulling Patients Data\n$baseUrl/queue/patients/\n$errorBody",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.errorColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void refreshList() {
|
||||
if (forceRefresh == true) {
|
||||
setState(() {
|
||||
accessRequestResults = fetchAccessRequests();
|
||||
forceRefresh = false;
|
||||
});
|
||||
} else if (selectedDropdown != filterController.text) {
|
||||
setState(() {
|
||||
accessRequestResults = fetchAccessRequests();
|
||||
selectedDropdown = filterController.text;
|
||||
});
|
||||
}
|
||||
// setState(() {
|
||||
// accessRequestResults = fetchAccessRequests();
|
||||
// });
|
||||
}
|
||||
|
||||
Widget displayQueueList(List<PatientQueue> patientQueueList) {
|
||||
if (patientQueueList.isNotEmpty) {
|
||||
return Expanded(
|
||||
child: BuildAppointmentList(
|
||||
patientQueue: patientQueueList,
|
||||
signedInUser: widget.signedInUser,
|
||||
),
|
||||
);
|
||||
}
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 35.0),
|
||||
child: Center(
|
||||
child: Text(
|
||||
"No Appointments for $selectedDay",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!.theme.messageTextColor(),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
softWrap: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void checkforchange() {
|
||||
setState(() {
|
||||
personalQueueResults = MIHApiCalls.fetchPersonalAppointmentsAPICall(
|
||||
selectedDay,
|
||||
widget.signedInUser.app_id,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
Navigator.of(context).popAndPushNamed(
|
||||
'/',
|
||||
arguments: true,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"Appointments",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: true,
|
||||
bodyItems: [
|
||||
MIHCalendar(
|
||||
calendarWidth: 500,
|
||||
rowHeight: 35,
|
||||
setDate: (value) {
|
||||
setState(() {
|
||||
selectedDay = value;
|
||||
appointmentDateController.text = selectedDay;
|
||||
});
|
||||
}),
|
||||
Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
FutureBuilder(
|
||||
future: personalQueueResults,
|
||||
builder: (context, snapshot) {
|
||||
//return displayQueueList(snapshot.requireData);
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Expanded(
|
||||
child: Center(child: Mihloadingcircle()));
|
||||
} else if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return displayQueueList(snapshot.requireData);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"Error pulling appointments",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.errorColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
}),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
filterController.dispose();
|
||||
appointmentDateController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// selectedDropdown = "All";
|
||||
// filterController.text = "All";
|
||||
// filterController.addListener(refreshList);
|
||||
// setState(() {
|
||||
// accessRequestResults = fetchAccessRequests();
|
||||
// });
|
||||
appointmentDateController.addListener(checkforchange);
|
||||
setState(() {
|
||||
personalQueueResults = MIHApiCalls.fetchPersonalAppointmentsAPICall(
|
||||
selectedDay,
|
||||
widget.signedInUser.app_id,
|
||||
);
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../../mih_components/mih_layout/mih_window.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_warning_message.dart';
|
||||
import '../../../mih_env/env.dart';
|
||||
import '../../../mih_objects/access_request.dart';
|
||||
import '../../../mih_objects/app_user.dart';
|
||||
|
||||
class BuildAccessRequestList extends StatefulWidget {
|
||||
final List<AccessRequest> accessRequests;
|
||||
final AppUser signedInUser;
|
||||
|
||||
const BuildAccessRequestList({
|
||||
super.key,
|
||||
required this.accessRequests,
|
||||
required this.signedInUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildAccessRequestList> createState() => _BuildPatientsListState();
|
||||
}
|
||||
|
||||
class _BuildPatientsListState extends State<BuildAccessRequestList> {
|
||||
String baseAPI = AppEnviroment.baseApiUrl;
|
||||
late double popUpWidth;
|
||||
late double? popUpheight;
|
||||
late double popUpButtonWidth;
|
||||
late double popUpTitleSize;
|
||||
late double popUpSubtitleSize;
|
||||
late double popUpBodySize;
|
||||
late double popUpIconSize;
|
||||
late double popUpPaddingSize;
|
||||
late double width;
|
||||
late double height;
|
||||
|
||||
Future<void> updateAccessAPICall(int index, String accessType) async {
|
||||
var response = await http.put(
|
||||
Uri.parse("$baseAPI/access-requests/update/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": widget.accessRequests[index].business_id,
|
||||
"app_id": widget.accessRequests[index].app_id,
|
||||
"date_time": widget.accessRequests[index].date_time,
|
||||
"access": accessType,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
//Navigator.of(context).pushNamed('/home');
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed(
|
||||
'/patient-access-review',
|
||||
arguments: widget.signedInUser,
|
||||
);
|
||||
String message = "";
|
||||
if (accessType == "approved") {
|
||||
message =
|
||||
"You've successfully approved the access request! ${widget.accessRequests[index].Name} now has access to your profile until ${widget.accessRequests[index].revoke_date.substring(0, 16).replaceAll("T", " ")}.";
|
||||
} else {
|
||||
message =
|
||||
"You've declined the access request. ${widget.accessRequests[index].Name} will not have access to your profile.";
|
||||
}
|
||||
successPopUp(message);
|
||||
} 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 accessCancelledWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "Access Cancelled");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget displayQueue(int index) {
|
||||
String line1 =
|
||||
"Appointment: ${widget.accessRequests[index].date_time.substring(0, 16).replaceAll("T", " ")}";
|
||||
String line2 = "";
|
||||
line2 += "Requestor: ${widget.accessRequests[index].Name}\n";
|
||||
//subtitle += "Business Type: ${widget.accessRequests[index].type}\n";
|
||||
String line3 = "Access: ";
|
||||
String access = "";
|
||||
var nowDate = DateTime.now();
|
||||
var expireyDate = DateTime.parse(widget.accessRequests[index].revoke_date);
|
||||
|
||||
if (expireyDate.isBefore(nowDate)) {
|
||||
access += "EXPIRED";
|
||||
} else {
|
||||
access += "${widget.accessRequests[index].access.toUpperCase()}";
|
||||
}
|
||||
String line4 = "";
|
||||
if (widget.accessRequests[index].revoke_date.contains("9999")) {
|
||||
line4 += "Access Expiration date: NOT SET";
|
||||
} else {
|
||||
line4 +=
|
||||
"Access Expiration date: ${widget.accessRequests[index].revoke_date.substring(0, 10)}";
|
||||
}
|
||||
TextSpan accessWithColour;
|
||||
if (access == "APPROVED") {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.successColor()));
|
||||
} else if (access == "PENDING") {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.messageTextColor()));
|
||||
} else {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor()));
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
title: Text(
|
||||
line1,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
subtitle: RichText(
|
||||
text: TextSpan(
|
||||
text: line2,
|
||||
style: DefaultTextStyle.of(context).style,
|
||||
children: <TextSpan>[
|
||||
TextSpan(text: line3),
|
||||
accessWithColour,
|
||||
TextSpan(text: line4),
|
||||
]),
|
||||
),
|
||||
// Text(
|
||||
// subtitle,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
onTap: () {
|
||||
if (access == "CANCELLED") {
|
||||
accessCancelledWarning();
|
||||
} else {
|
||||
viewApprovalPopUp(index);
|
||||
}
|
||||
},
|
||||
// trailing: Icon(
|
||||
// Icons.arrow_forward,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
);
|
||||
}
|
||||
|
||||
void checkScreenSize() {
|
||||
if (MzanziInnovationHub.of(context)!.theme.screenType == "desktop") {
|
||||
setState(() {
|
||||
popUpWidth = (width / 4) * 2;
|
||||
popUpheight = null;
|
||||
popUpButtonWidth = 300;
|
||||
popUpTitleSize = 25.0;
|
||||
popUpSubtitleSize = 20.0;
|
||||
popUpBodySize = 15;
|
||||
popUpPaddingSize = 25.0;
|
||||
popUpIconSize = 100;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
popUpWidth = width - (width * 0.1);
|
||||
popUpheight = null;
|
||||
popUpButtonWidth = 300;
|
||||
popUpTitleSize = 20.0;
|
||||
popUpSubtitleSize = 18.0;
|
||||
popUpBodySize = 15;
|
||||
popUpPaddingSize = 15.0;
|
||||
popUpIconSize = 100;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void viewApprovalPopUp(int index) {
|
||||
String subtitle =
|
||||
"Appointment: ${widget.accessRequests[index].date_time.substring(0, 16).replaceAll("T", " ")}\n";
|
||||
subtitle += "Requestor: ${widget.accessRequests[index].Name}\n";
|
||||
subtitle += "Business Type: ${widget.accessRequests[index].type}\n\n";
|
||||
subtitle +=
|
||||
"You are about to approve an access request to your patient profile.\nPlease be aware that once approved, ${widget.accessRequests[index].Name} will have access to your profile information until ${widget.accessRequests[index].revoke_date.substring(0, 16).replaceAll("T", " ")}.\nIf you are unsure about an upcoming appointment with ${widget.accessRequests[index].Name}, please contact ${widget.accessRequests[index].contact_no} for clarification before approving this request.\n";
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Update Appointment Access",
|
||||
windowBody: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Text(
|
||||
subtitle,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
fontSize: popUpBodySize,
|
||||
//fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
Wrap(
|
||||
runSpacing: 10,
|
||||
spacing: 10,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: popUpButtonWidth,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
updateAccessAPICall(index, "declined");
|
||||
},
|
||||
buttonText: "Decline",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: popUpButtonWidth,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
updateAccessAPICall(index, "approved");
|
||||
},
|
||||
buttonText: "Approve",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.successColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
windowTools: const [],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
}),
|
||||
);
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => Dialog(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// Container(
|
||||
// //padding: const EdgeInsets.all(15.0),
|
||||
// width: popUpWidth,
|
||||
// height: popUpheight,
|
||||
// decoration: BoxDecoration(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
// borderRadius: BorderRadius.circular(25.0),
|
||||
// border: Border.all(
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// width: 5.0),
|
||||
// ),
|
||||
// child: SingleChildScrollView(
|
||||
// padding: EdgeInsets.all(popUpPaddingSize),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Update Appointment Access",
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// fontSize: popUpTitleSize,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 15.0),
|
||||
// Text(
|
||||
// subtitle,
|
||||
// textAlign: TextAlign.left,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// fontSize: popUpBodySize,
|
||||
// //fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// Wrap(
|
||||
// runSpacing: 10,
|
||||
// spacing: 10,
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// width: popUpButtonWidth,
|
||||
// height: 50,
|
||||
// child: MIHButton(
|
||||
// onTap: () {
|
||||
// updateAccessAPICall(index, "declined");
|
||||
// },
|
||||
// buttonText: "Decline",
|
||||
// buttonColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .errorColor(),
|
||||
// textColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .primaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: popUpButtonWidth,
|
||||
// height: 50,
|
||||
// child: MIHButton(
|
||||
// onTap: () {
|
||||
// updateAccessAPICall(index, "approved");
|
||||
// },
|
||||
// buttonText: "Approve",
|
||||
// buttonColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .successColor(),
|
||||
// textColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .primaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 5,
|
||||
// right: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pop(context);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.close,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var size = MediaQuery.of(context).size;
|
||||
setState(() {
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
});
|
||||
checkScreenSize();
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
separatorBuilder: (BuildContext context, index) {
|
||||
return Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
);
|
||||
},
|
||||
itemCount: widget.accessRequests.length,
|
||||
itemBuilder: (context, index) {
|
||||
//final patient = widget.patients[index].id_no.contains(widget.searchString);
|
||||
//print(index);
|
||||
return displayQueue(index);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_warning_message.dart';
|
||||
import '../../../mih_env/env.dart';
|
||||
import '../../../mih_objects/app_user.dart';
|
||||
import '../../../mih_objects/patient_queue.dart';
|
||||
|
||||
class BuildAppointmentList extends StatefulWidget {
|
||||
final List<PatientQueue> patientQueue;
|
||||
final AppUser signedInUser;
|
||||
|
||||
const BuildAppointmentList({
|
||||
super.key,
|
||||
required this.patientQueue,
|
||||
required this.signedInUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildAppointmentList> createState() => _BuildPatientsListState();
|
||||
}
|
||||
|
||||
class _BuildPatientsListState extends State<BuildAppointmentList> {
|
||||
String baseAPI = AppEnviroment.baseApiUrl;
|
||||
TextEditingController dateController = TextEditingController();
|
||||
TextEditingController timeController = TextEditingController();
|
||||
TextEditingController idController = TextEditingController();
|
||||
TextEditingController fnameController = TextEditingController();
|
||||
TextEditingController lnameController = TextEditingController();
|
||||
TextEditingController daysExtensionController = TextEditingController();
|
||||
int counter = 0;
|
||||
|
||||
Widget displayQueue(int index) {
|
||||
String title = widget.patientQueue[index].business_name.toUpperCase();
|
||||
// widget.patientQueue[index].date_time.split('T')[1].substring(0, 5);
|
||||
String line234 = "";
|
||||
// var nowDate = DateTime.now();
|
||||
// var expireyDate = DateTime.parse(widget.patientQueue[index].revoke_date);
|
||||
|
||||
line234 +=
|
||||
widget.patientQueue[index].date_time.split('T')[1].substring(0, 5);
|
||||
|
||||
return ListTile(
|
||||
title: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
subtitle: RichText(
|
||||
text: TextSpan(
|
||||
text: "Time: $line234",
|
||||
style: DefaultTextStyle.of(context).style,
|
||||
// children: [
|
||||
// TextSpan(text: line5),
|
||||
// accessWithColour,
|
||||
// TextSpan(text: line6),
|
||||
// ]
|
||||
),
|
||||
),
|
||||
onTap: () {},
|
||||
);
|
||||
}
|
||||
|
||||
bool isAccessExpired(String accessType) {
|
||||
if (accessType == "EXPIRED") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void noAccessWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "No Access");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void accessDeclinedWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "Access Declined");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void appointmentCancelledWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "Appointment Canelled");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void expiredAccessWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "Expired Access");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
daysExtensionController.dispose();
|
||||
dateController.dispose();
|
||||
timeController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.separated(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
separatorBuilder: (BuildContext context, index) {
|
||||
return Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
);
|
||||
},
|
||||
itemCount: widget.patientQueue.length,
|
||||
itemBuilder: (context, index) {
|
||||
//final patient = widget.patients[index].id_no.contains(widget.searchString);
|
||||
//print(index);
|
||||
|
||||
return displayQueue(index);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
67
Frontend/lib/mih_packages/authentication/auth_check.dart
Normal file
67
Frontend/lib/mih_packages/authentication/auth_check.dart
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
|
||||
import '../mih_home/mih_profile_getter.dart';
|
||||
import 'signin_or_register.dart';
|
||||
|
||||
class AuthCheck extends StatefulWidget {
|
||||
final bool personalSelected;
|
||||
const AuthCheck({
|
||||
super.key,
|
||||
required this.personalSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AuthCheck> createState() => _AuthCheckState();
|
||||
}
|
||||
|
||||
class _AuthCheckState extends State<AuthCheck> {
|
||||
Future<bool> doesSessionExist() async {
|
||||
//wait
|
||||
//await Future.delayed(const Duration(seconds: 1));
|
||||
bool signedIn = await SuperTokens.doesSessionExist();
|
||||
return signedIn;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
//signedIn = doesSessionExist();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: OrientationBuilder(
|
||||
builder: (BuildContext context, Orientation orientation) {
|
||||
// Return a widget tree based on the orientation
|
||||
return FutureBuilder(
|
||||
future: doesSessionExist(),
|
||||
builder: (context, snapshot) {
|
||||
//print(snapshot.data);
|
||||
if (snapshot.data == true) {
|
||||
return MIHProfileGetter(
|
||||
personalSelected: widget.personalSelected,
|
||||
);
|
||||
} else if (snapshot.data == false) {
|
||||
return const SignInOrRegister();
|
||||
} else {
|
||||
return const SizedBox(width: 5, height: 5);
|
||||
//const Mihloadingcircle();
|
||||
}
|
||||
});
|
||||
},
|
||||
// child: FutureBuilder(
|
||||
// future: signedIn,
|
||||
// builder: (context, snapshot) {
|
||||
// if (snapshot.data == true) {
|
||||
// return const MIHProfileGetter();
|
||||
// } else {
|
||||
// return const SignInOrRegister();
|
||||
// }
|
||||
// }),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
367
Frontend/lib/mih_packages/authentication/forgot_password.dart
Normal file
367
Frontend/lib/mih_packages/authentication/forgot_password.dart
Normal file
@@ -0,0 +1,367 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supabase_auth_ui/supabase_auth_ui.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
|
||||
class ForgotPassword extends StatefulWidget {
|
||||
const ForgotPassword({super.key});
|
||||
|
||||
@override
|
||||
State<ForgotPassword> createState() => _ForgotPasswordState();
|
||||
}
|
||||
|
||||
class _ForgotPasswordState extends State<ForgotPassword> {
|
||||
final emailController = TextEditingController();
|
||||
|
||||
//bool _obscureText = true;
|
||||
bool successfulForgotPassword = false;
|
||||
bool acceptWarning = false;
|
||||
// focus node to capture keyboard events
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
Future<void> submitPasswodReset() async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
var response = await http.post(
|
||||
Uri.parse("$baseAPI/auth/user/password/reset/token"),
|
||||
body:
|
||||
'{"formFields": [{"id": "email","value": "${emailController.text}"}]}',
|
||||
headers: {
|
||||
'Content-type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
//"Authorization": "leatucczyixqwkqqdrhayiwzeofkltds"
|
||||
},
|
||||
);
|
||||
//print(response.body[])
|
||||
if (response.statusCode == 200) {
|
||||
//print(response.body);
|
||||
var userSignedin = jsonDecode(response.body);
|
||||
if (userSignedin["status"] == "OK") {
|
||||
//print("here");
|
||||
setState(() {
|
||||
successfulForgotPassword = true;
|
||||
});
|
||||
Navigator.of(context).pop();
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
//loginError();
|
||||
}
|
||||
}
|
||||
} on AuthException {
|
||||
Navigator.of(context).pop();
|
||||
//loginError();
|
||||
}
|
||||
}
|
||||
|
||||
Color getPrim() {
|
||||
return MzanziInnovationHub.of(context)!.theme.secondaryColor();
|
||||
}
|
||||
|
||||
Color getSec() {
|
||||
return MzanziInnovationHub.of(context)!.theme.primaryColor();
|
||||
}
|
||||
|
||||
void prePassResteWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Dialog(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
width: 500.0,
|
||||
height: 450,
|
||||
decoration: BoxDecoration(
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
border: Border.all(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
width: 5.0),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
//mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
size: 100,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
" Password Reset Confirmation",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 25.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25.0),
|
||||
child: Text(
|
||||
"Before you reset your password, please be aware that you'll receive an email with a link to confirm your identity and set a new password. Make sure to check your inbox, including spam or junk folders. If you don't receive the email within a few minutes, please try resending the reset request.",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Continue",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.primaryColor(),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
acceptWarning = true;
|
||||
});
|
||||
Navigator.of(context).pop();
|
||||
validateInput();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
right: 5,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.close,
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void loginError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Invalid Credentials");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void resetLinkSentSuccessfully() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHSuccessMessage(
|
||||
successType: "Success",
|
||||
successMessage:
|
||||
"We've sent a password reset link to your email address. Please check your inbox, including spam or junk folders.\n\nOnce you find the email, click on the link to reset your password.\n\nIf you don't receive the email within a few minutes, please try resending the reset request.\n\nThe reset link will expire after 2 hours");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void validateInput() async {
|
||||
if (emailController.text.isEmpty) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await submitPasswodReset();
|
||||
if (successfulForgotPassword) {
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
|
||||
resetLinkSentSuccessfully();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: false,
|
||||
bodyItems: [
|
||||
KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
validateInput();
|
||||
}
|
||||
},
|
||||
child: SafeArea(
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(25.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
//logo
|
||||
Icon(
|
||||
Icons.lock,
|
||||
size: 100,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
//Heading
|
||||
Text(
|
||||
'Forgot Password',
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 25),
|
||||
|
||||
//email input
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
child: MIHTextField(
|
||||
controller: emailController,
|
||||
hintText: 'Email',
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
),
|
||||
|
||||
//spacer
|
||||
const SizedBox(height: 30),
|
||||
// sign in button
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Reset Password",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.primaryColor(),
|
||||
onTap: () {
|
||||
prePassResteWarning();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
emailController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
}
|
||||
}
|
||||
429
Frontend/lib/mih_packages/authentication/register.dart
Normal file
429
Frontend/lib/mih_packages/authentication/register.dart
Normal file
@@ -0,0 +1,429 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
//import '../objects/sessionST.dart';
|
||||
import 'package:supabase_auth_ui/supabase_auth_ui.dart';
|
||||
//import 'package:supertokens_flutter/supertokens.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_pass_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
|
||||
class Register extends StatefulWidget {
|
||||
final Function()? onTap;
|
||||
const Register({super.key, required this.onTap});
|
||||
|
||||
@override
|
||||
State<Register> createState() => _RegisterState();
|
||||
}
|
||||
|
||||
class _RegisterState extends State<Register> {
|
||||
final emailController = TextEditingController();
|
||||
final passwordController = TextEditingController();
|
||||
final confirmPasswordController = TextEditingController();
|
||||
final officeID = TextEditingController();
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
bool _obscureText = true;
|
||||
|
||||
bool successfulSignUp = false;
|
||||
|
||||
Future<void> addUserAPICall(String email, String uid) async {
|
||||
//await getOfficeIdByUser(docOfficeIdApiUrl + widget.userEmail);
|
||||
//print(futureDocOfficeId.toString());
|
||||
var response = await http.post(
|
||||
Uri.parse("$baseAPI/user/insert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"email": email,
|
||||
"app_id": uid,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 201) {
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
|
||||
signUpSuccess();
|
||||
// setState(() {
|
||||
// successfulSignUp = true;
|
||||
// });
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
//sign user in
|
||||
Future<void> signUserUp() async {
|
||||
if (!validEmail()) {
|
||||
emailError();
|
||||
} else if (passwordController.text != confirmPasswordController.text) {
|
||||
passwordError();
|
||||
} else {
|
||||
//var _backgroundColor = Colors.transparent;
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
Uri uri = Uri.parse(
|
||||
"$baseAPI/auth/emailpassword/email/exists?email=${emailController.text}");
|
||||
//print("Here");
|
||||
var response = await http.get(uri);
|
||||
//print(response.body);
|
||||
//print("response 1: ${response.statusCode}");
|
||||
if (response.statusCode == 200) {
|
||||
var userExists = jsonDecode(response.body);
|
||||
if (userExists["exists"]) {
|
||||
signUpError();
|
||||
} else {
|
||||
var response2 = await http.post(
|
||||
Uri.parse("$baseAPI/auth/signup"),
|
||||
body:
|
||||
'{"formFields": [{"id": "email","value": "${emailController.text}"}, {"id": "password","value": "${passwordController.text}"}]}',
|
||||
headers: {
|
||||
'Content-type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
"Authorization": "leatucczyixqwkqqdrhayiwzeofkltds"
|
||||
},
|
||||
);
|
||||
//print("response 2: ${response2.statusCode}");
|
||||
if (response2.statusCode == 200) {
|
||||
//print("response 2: ${response2.body}");
|
||||
var userCreated = jsonDecode(response2.body);
|
||||
//print("Created user $userCreated");
|
||||
if (userCreated["status"] == "OK") {
|
||||
//print("Here1");
|
||||
//Creat user in db
|
||||
String uid = await SuperTokens.getUserId();
|
||||
//print("uid: $uid");
|
||||
addUserAPICall(emailController.text, uid);
|
||||
Navigator.of(context).pop();
|
||||
//print("Here1");
|
||||
} else if (userCreated["status"] == "FIELD_ERROR") {
|
||||
Navigator.of(context).pop();
|
||||
passwordReqError();
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} on AuthException catch (error) {
|
||||
Navigator.of(context).pop();
|
||||
loginError(error.message);
|
||||
emailController.clear();
|
||||
passwordController.clear();
|
||||
confirmPasswordController.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool validEmail() {
|
||||
String text = emailController.text;
|
||||
var regex = RegExp(r'^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$');
|
||||
return regex.hasMatch(text);
|
||||
}
|
||||
|
||||
void internetConnectionPopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Internet Connection");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void signUpSuccess() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHSuccessMessage(
|
||||
successType: "Success",
|
||||
successMessage:
|
||||
"Congratulations! Your account has been created successfully. You are logged in and can start exploring.\n\nPlease note: more apps will appear once you update your profile.");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void signUpError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "User Exists");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void passwordError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Password Match");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void emailError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Invalid Email");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void passwordReqError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Password Requirements");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void loginError(error) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(error),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void validateInput() async {
|
||||
if (emailController.text.isEmpty ||
|
||||
passwordController.text.isEmpty ||
|
||||
confirmPasswordController.text.isEmpty) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await signUserUp();
|
||||
}
|
||||
}
|
||||
|
||||
void toggle() {
|
||||
setState(() {
|
||||
_obscureText = !_obscureText;
|
||||
});
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: SizedBox(
|
||||
height: 50,
|
||||
child: Image.asset('images/logo_light.png'),
|
||||
),
|
||||
),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/about',
|
||||
//arguments: widget.signedInUser,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: false,
|
||||
bodyItems: [
|
||||
KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
validateInput();
|
||||
}
|
||||
},
|
||||
child: SafeArea(
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(25.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
//logo
|
||||
Icon(
|
||||
Icons.lock,
|
||||
size: 100,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
//Heading
|
||||
Text(
|
||||
'Register',
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 25),
|
||||
//email input
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
child: MIHTextField(
|
||||
controller: emailController,
|
||||
hintText: 'Email',
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
//password input
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
child: MIHPassField(
|
||||
controller: passwordController,
|
||||
hintText: 'Password',
|
||||
required: true,
|
||||
signIn: false,
|
||||
),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
//password input
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
child: MIHPassField(
|
||||
controller: confirmPasswordController,
|
||||
hintText: 'Confirm Password',
|
||||
required: true,
|
||||
signIn: false,
|
||||
),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 30),
|
||||
// sign up button
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Sign Up",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.primaryColor(),
|
||||
onTap: () async {
|
||||
validateInput();
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
//register text
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
//height: 100.0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
const Text(
|
||||
'Already a User?',
|
||||
style: TextStyle(fontSize: 18, color: Colors.grey),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 6,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
child: Text(
|
||||
'Sign In',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
emailController.dispose();
|
||||
passwordController.dispose();
|
||||
officeID.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
}
|
||||
}
|
||||
431
Frontend/lib/mih_packages/authentication/reset_password.dart
Normal file
431
Frontend/lib/mih_packages/authentication/reset_password.dart
Normal file
@@ -0,0 +1,431 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supabase_auth_ui/supabase_auth_ui.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_pass_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
|
||||
class ResetPassword extends StatefulWidget {
|
||||
final String? token;
|
||||
const ResetPassword({
|
||||
super.key,
|
||||
required this.token,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ResetPassword> createState() => _ResetPasswordState();
|
||||
}
|
||||
|
||||
class _ResetPasswordState extends State<ResetPassword> {
|
||||
final passwordController = TextEditingController();
|
||||
final confirmPasswordController = TextEditingController();
|
||||
|
||||
//bool _obscureText = true;
|
||||
bool successfulResetPassword = false;
|
||||
bool acceptWarning = false;
|
||||
// focus node to capture keyboard events
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
Future<void> submitPasswodReset() async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
var callBody =
|
||||
'{"method": "token","formFields": [{"id": "password","value": "${passwordController.text}"}],"token": "${widget.token}"}';
|
||||
//print(callBody);
|
||||
var response = await http.post(
|
||||
Uri.parse("$baseAPI/auth/user/password/reset"),
|
||||
body: callBody,
|
||||
headers: {
|
||||
'Content-type': 'application/json; charset=utf-8',
|
||||
// 'Accept': 'application/json',
|
||||
//"Authorization": "leatucczyixqwkqqdrhayiwzeofkltds"
|
||||
},
|
||||
);
|
||||
//print(response.body[])
|
||||
if (response.statusCode == 200) {
|
||||
//print(response.body);
|
||||
var userPassReset = jsonDecode(response.body);
|
||||
if (userPassReset["status"] == "OK") {
|
||||
//print("here");
|
||||
setState(() {
|
||||
successfulResetPassword = true;
|
||||
});
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed('/');
|
||||
} else if (userPassReset["status"] == "FIELD_ERROR") {
|
||||
Navigator.of(context).pop();
|
||||
passwordReqError();
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
loginError();
|
||||
}
|
||||
}
|
||||
} on AuthException {
|
||||
Navigator.of(context).pop();
|
||||
//loginError();
|
||||
}
|
||||
}
|
||||
|
||||
void passwordReqError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Password Requirements");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Color getPrim() {
|
||||
return MzanziInnovationHub.of(context)!.theme.secondaryColor();
|
||||
}
|
||||
|
||||
Color getSec() {
|
||||
return MzanziInnovationHub.of(context)!.theme.primaryColor();
|
||||
}
|
||||
|
||||
void prePassResteWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Dialog(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
width: 500.0,
|
||||
height: 450,
|
||||
decoration: BoxDecoration(
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
border: Border.all(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
width: 5.0),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
//mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
size: 100,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
"Password Reset Confirmation",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 25.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25.0),
|
||||
child: Text(
|
||||
"Before you reset your password, please be aware that you'll receive an email with a link to confirm your identity and set a new password. Make sure to check your inbox, including spam or junk folders. If you don't receive the email within a few minutes, please try resending the reset request.",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Continue",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.primaryColor(),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
acceptWarning = true;
|
||||
});
|
||||
Navigator.of(context).pop();
|
||||
validateInput();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
right: 5,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.close,
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void loginError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Invalid Credentials");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void resetSuccessfully() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHSuccessMessage(
|
||||
successType: "Success",
|
||||
successMessage:
|
||||
"Great news! Your password reset is complete. You can now log in to Mzansi Innovation Hub using your new password.");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void passwordError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Password Match");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void validateInput() async {
|
||||
if (passwordController.text.isEmpty ||
|
||||
confirmPasswordController.text.isEmpty) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
} else if (passwordController.text != confirmPasswordController.text) {
|
||||
passwordError();
|
||||
} else {
|
||||
await submitPasswodReset();
|
||||
if (successfulResetPassword) {
|
||||
resetSuccessfully();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: SizedBox(
|
||||
height: 50,
|
||||
child: Image.asset('images/logo_light.png'),
|
||||
),
|
||||
),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
// Navigator.of(context).pushNamed(
|
||||
// '/about',
|
||||
// //arguments: widget.signedInUser,
|
||||
// );
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: false,
|
||||
bodyItems: [
|
||||
KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
validateInput();
|
||||
}
|
||||
},
|
||||
child: SafeArea(
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(25.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
//logo
|
||||
Icon(
|
||||
Icons.lock,
|
||||
size: 100,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
//Heading
|
||||
Text(
|
||||
'Reset Password',
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
),
|
||||
//spacer
|
||||
// const SizedBox(height: 15),
|
||||
// Text(
|
||||
// 'token: ${widget.token}',
|
||||
// style: TextStyle(
|
||||
// fontSize: 15,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
//spacer
|
||||
const SizedBox(height: 25),
|
||||
//email input
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
child: MIHPassField(
|
||||
controller: passwordController,
|
||||
hintText: 'New Password',
|
||||
required: true,
|
||||
signIn: false,
|
||||
),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
//password input
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
child: MIHPassField(
|
||||
controller: confirmPasswordController,
|
||||
hintText: 'Confirm New Password',
|
||||
required: true,
|
||||
signIn: false,
|
||||
),
|
||||
),
|
||||
|
||||
//spacer
|
||||
const SizedBox(height: 30),
|
||||
// sign in button
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Reset Password",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.primaryColor(),
|
||||
onTap: () {
|
||||
validateInput();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
passwordController.dispose();
|
||||
confirmPasswordController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
}
|
||||
}
|
||||
618
Frontend/lib/mih_packages/authentication/signin.dart
Normal file
618
Frontend/lib/mih_packages/authentication/signin.dart
Normal file
@@ -0,0 +1,618 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supabase_auth_ui/supabase_auth_ui.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_pass_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_layout/mih_tile.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
|
||||
class SignIn extends StatefulWidget {
|
||||
final Function()? onTap;
|
||||
const SignIn({super.key, required this.onTap});
|
||||
|
||||
@override
|
||||
State<SignIn> createState() => _SignInState();
|
||||
}
|
||||
|
||||
class _SignInState extends State<SignIn> {
|
||||
final emailController = TextEditingController();
|
||||
final passwordController = TextEditingController();
|
||||
//bool _obscureText = true;
|
||||
bool successfulSignIn = false;
|
||||
bool showProfiles = false;
|
||||
|
||||
// focus node to capture keyboard events
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
late List<MIHTile> sandboxProfileList = [];
|
||||
|
||||
//sign user in
|
||||
Future<void> signUserIn() async {
|
||||
//var _backgroundColor = Colors.transparent;
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
var response = await http.post(
|
||||
Uri.parse("$baseAPI/auth/signin"),
|
||||
body:
|
||||
'{"formFields": [{"id": "email","value": "${emailController.text}"}, {"id": "password","value": "${passwordController.text}"}]}',
|
||||
headers: {
|
||||
'Content-type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
"Authorization": "leatucczyixqwkqqdrhayiwzeofkltds"
|
||||
},
|
||||
);
|
||||
//print(response.body[])
|
||||
if (response.statusCode == 200) {
|
||||
//print(response.body);
|
||||
var userSignedin = jsonDecode(response.body);
|
||||
if (userSignedin["status"] == "OK") {
|
||||
//print("here");
|
||||
setState(() {
|
||||
successfulSignIn = true;
|
||||
});
|
||||
Navigator.of(context).pop();
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
loginError();
|
||||
passwordController.clear();
|
||||
}
|
||||
}
|
||||
} on AuthException {
|
||||
Navigator.of(context).pop();
|
||||
loginError();
|
||||
passwordController.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Color getPrim() {
|
||||
return MzanziInnovationHub.of(context)!.theme.secondaryColor();
|
||||
}
|
||||
|
||||
Color getSec() {
|
||||
return MzanziInnovationHub.of(context)!.theme.primaryColor();
|
||||
}
|
||||
|
||||
void setSandboxProfiles(List<MIHTile> tileList) {
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
emailController.text = "testpatient@mzansi-innovation-hub.co.za";
|
||||
passwordController.text = "Testprofile@1234";
|
||||
});
|
||||
validateInput();
|
||||
},
|
||||
tileName: "Patient",
|
||||
tileIcon: Icon(
|
||||
Icons.perm_identity_rounded,
|
||||
color: getSec(),
|
||||
size: 200,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
emailController.text = "testdoctor@mzansi-innovation-hub.co.za";
|
||||
passwordController.text = "Testprofile@1234";
|
||||
});
|
||||
validateInput();
|
||||
},
|
||||
tileName: "Doctor",
|
||||
tileIcon: Icon(
|
||||
Icons.medical_services,
|
||||
color: getSec(),
|
||||
size: 200,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
//if (AppEnviroment.getEnv() == "Dev") {
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
emailController.text = "test-business@mzansi-innovation-hub.co.za";
|
||||
passwordController.text = "Testprofile@1234";
|
||||
});
|
||||
validateInput();
|
||||
},
|
||||
tileName: "Business",
|
||||
tileIcon: Icon(
|
||||
Icons.business,
|
||||
color: getSec(),
|
||||
size: 200,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
emailController.text = "test@mzansi-innovation-hub.co.za";
|
||||
passwordController.text = "Testprofile@1234";
|
||||
});
|
||||
validateInput();
|
||||
},
|
||||
tileName: "Test",
|
||||
tileIcon: Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color: getSec(),
|
||||
size: 200,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
//}
|
||||
}
|
||||
|
||||
void loginError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Invalid Credentials");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void validateInput() async {
|
||||
if (emailController.text.isEmpty || passwordController.text.isEmpty) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await signUserIn();
|
||||
if (successfulSignIn) {
|
||||
TextInput.finishAutofillContext();
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showSandboxProfiles() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Dialog(
|
||||
//backgroundColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
width: 500.0,
|
||||
height: 500,
|
||||
decoration: BoxDecoration(
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
border: Border.all(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
width: 5.0),
|
||||
),
|
||||
child: Column(
|
||||
//mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Text(
|
||||
"Sandbox Profiles",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 25.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"NB: These accounts are used for test purposes. Please do not store personal information on these profiles.",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Expanded(
|
||||
child: GridView.builder(
|
||||
// physics: ,
|
||||
// shrinkWrap: true,
|
||||
itemCount: sandboxProfileList.length,
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
mainAxisSpacing: 10, maxCrossAxisExtent: 100),
|
||||
itemBuilder: (context, index) {
|
||||
return sandboxProfileList[index];
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
right: 5,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.close,
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: SizedBox(
|
||||
height: 50,
|
||||
child: Image.asset('images/logo_light.png'),
|
||||
),
|
||||
),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/about',
|
||||
//arguments: widget.signedInUser,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: false,
|
||||
bodyItems: [
|
||||
KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
validateInput();
|
||||
}
|
||||
},
|
||||
child: SafeArea(
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(25.0),
|
||||
child: AutofillGroup(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
//logo
|
||||
Icon(
|
||||
Icons.lock,
|
||||
size: 100,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
//Heading
|
||||
Text(
|
||||
'Sign In',
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 25),
|
||||
|
||||
// SizedBox(
|
||||
// width: 500.0,
|
||||
// //height: 100.0,
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// children: [
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// showSandboxProfiles();
|
||||
// },
|
||||
// child: Text(
|
||||
// 'Sandbox Profile',
|
||||
// style: TextStyle(
|
||||
// fontSize: 18,
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10),
|
||||
//email input
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
child: MIHTextField(
|
||||
controller: emailController,
|
||||
hintText: 'Email',
|
||||
editable: true,
|
||||
required: true,
|
||||
autoFillHintGroup: const [AutofillHints.email],
|
||||
),
|
||||
),
|
||||
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
//password input
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
child: MIHPassField(
|
||||
controller: passwordController,
|
||||
hintText: 'Password',
|
||||
required: true,
|
||||
signIn: true,
|
||||
autoFillHintGroup: const [AutofillHints.password],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
//height: 100.0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/forgot-password',
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'Forgot Password?',
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
//spacer
|
||||
const SizedBox(height: 30),
|
||||
// sign in button
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Sign In",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.primaryColor(),
|
||||
onTap: () async {
|
||||
validateInput();
|
||||
},
|
||||
),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
//register text
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
//height: 100.0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
'New User?',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.messageTextColor()),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 6,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
child: Text(
|
||||
'Register Now',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 15),
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
//height: 100.0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Flexible(
|
||||
flex: 1,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(right: 10.0),
|
||||
child: Divider(),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: GestureDetector(
|
||||
child: Text(
|
||||
'Use Sandox Profile',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor()),
|
||||
),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
showProfiles = !showProfiles;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
const Flexible(
|
||||
flex: 1,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 10.0),
|
||||
child: Divider(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Visibility(
|
||||
visible: showProfiles,
|
||||
child: SizedBox(
|
||||
width: 500,
|
||||
child: Column(
|
||||
//mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
GridView.builder(
|
||||
// physics: ,
|
||||
shrinkWrap: true,
|
||||
itemCount: sandboxProfileList.length,
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
mainAxisSpacing: 10,
|
||||
maxCrossAxisExtent: 100),
|
||||
itemBuilder: (context, index) {
|
||||
return sandboxProfileList[index];
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
"NB: These accounts are used for test purposes. Please do not store personal information on these profiles.",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
emailController.dispose();
|
||||
passwordController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
setState(() {
|
||||
setSandboxProfiles(sandboxProfileList);
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'register.dart';
|
||||
import 'signin.dart';
|
||||
|
||||
class SignInOrRegister extends StatefulWidget {
|
||||
const SignInOrRegister({super.key});
|
||||
|
||||
@override
|
||||
State<SignInOrRegister> createState() => _SignInOrRegisterState();
|
||||
}
|
||||
|
||||
class _SignInOrRegisterState extends State<SignInOrRegister> {
|
||||
bool showSignInPage = true;
|
||||
|
||||
void togglePages() {
|
||||
setState(() {
|
||||
showSignInPage = !showSignInPage;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (showSignInPage) {
|
||||
return SignIn(onTap: togglePages);
|
||||
} else {
|
||||
return Register(onTap: togglePages);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../../mih_components/mih_layout/mih_window.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_delete_message.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../../mih_env/env.dart';
|
||||
import '../../../mih_objects/arguments.dart';
|
||||
import '../../../mih_objects/business_employee.dart';
|
||||
|
||||
class BuildEmployeeList extends StatefulWidget {
|
||||
final List<BusinessEmployee> employees;
|
||||
final BusinessArguments arguments;
|
||||
|
||||
const BuildEmployeeList({
|
||||
super.key,
|
||||
required this.employees,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildEmployeeList> createState() => _BuildEmployeeListState();
|
||||
}
|
||||
|
||||
class _BuildEmployeeListState extends State<BuildEmployeeList> {
|
||||
TextEditingController accessController = TextEditingController();
|
||||
TextEditingController typeController = TextEditingController();
|
||||
TextEditingController fnameController = TextEditingController();
|
||||
TextEditingController lnameController = TextEditingController();
|
||||
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
Future<void> updateEmployeeAPICall(int index) async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
var response = await http.put(
|
||||
Uri.parse("$baseAPI/business-user/employees/update/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": widget.employees[index].business_id,
|
||||
"app_id": widget.employees[index].app_id,
|
||||
"title": typeController.text,
|
||||
"access": accessController.text,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
//setState(() {});
|
||||
Navigator.of(context).pushNamed(
|
||||
'/business-profile/manage',
|
||||
arguments: BusinessArguments(
|
||||
widget.arguments.signedInUser,
|
||||
widget.arguments.businessUser,
|
||||
widget.arguments.business,
|
||||
),
|
||||
);
|
||||
String message = "Your employees details have been updated.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteNoteApiCall(int index) async {
|
||||
var response = await http.delete(
|
||||
Uri.parse("$baseAPI/business-user/employees/delete/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": widget.employees[index].business_id,
|
||||
"app_id": widget.employees[index].app_id,
|
||||
}),
|
||||
);
|
||||
//print("Here4");
|
||||
//print(response.statusCode);
|
||||
if (response.statusCode == 200) {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed(
|
||||
'/business-profile/manage',
|
||||
arguments: BusinessArguments(
|
||||
widget.arguments.signedInUser,
|
||||
widget.arguments.businessUser,
|
||||
widget.arguments.business,
|
||||
),
|
||||
);
|
||||
String message =
|
||||
"The employee has been deleted successfully. This means it will no longer have access to your business profile";
|
||||
successPopUp(message);
|
||||
} 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,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool isRequiredFieldsCaptured() {
|
||||
if (accessController.text.isEmpty || typeController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void updateEmployeePopUp(int index) {
|
||||
setState(() {
|
||||
accessController.text = widget.employees[index].access;
|
||||
typeController.text = widget.employees[index].title;
|
||||
fnameController.text = widget.employees[index].fname;
|
||||
lnameController.text = widget.employees[index].lname;
|
||||
});
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Employee Details",
|
||||
windowTools: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
showDeleteWarning(index);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.delete,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
windowBody: [
|
||||
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),
|
||||
MIHDropdownField(
|
||||
controller: typeController,
|
||||
hintText: "Title",
|
||||
dropdownOptions: const ["Doctor", "Assistant"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: accessController,
|
||||
hintText: "Access",
|
||||
dropdownOptions: const ["Full", "Partial"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
buttonText: "Update",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
onTap: () {
|
||||
if (isRequiredFieldsCaptured()) {
|
||||
updateEmployeeAPICall(index);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => Dialog(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// Container(
|
||||
// padding: const EdgeInsets.all(10.0),
|
||||
// width: 700.0,
|
||||
// //height: 475.0,
|
||||
// decoration: BoxDecoration(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
// borderRadius: BorderRadius.circular(25.0),
|
||||
// border: Border.all(
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// width: 5.0),
|
||||
// ),
|
||||
// child: SingleChildScrollView(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Employee Details",
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// fontSize: 35.0,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 25.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),
|
||||
// MIHDropdownField(
|
||||
// controller: typeController,
|
||||
// hintText: "Title",
|
||||
// dropdownOptions: const ["Doctor", "Assistant"],
|
||||
// required: true,
|
||||
// editable: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHDropdownField(
|
||||
// controller: accessController,
|
||||
// hintText: "Access",
|
||||
// dropdownOptions: const ["Full", "Partial"],
|
||||
// required: true,
|
||||
// editable: true,
|
||||
// ),
|
||||
// const SizedBox(height: 30.0),
|
||||
// SizedBox(
|
||||
// width: 300,
|
||||
// height: 50,
|
||||
// child: MIHButton(
|
||||
// buttonText: "Update",
|
||||
// buttonColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// textColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .primaryColor(),
|
||||
// onTap: () {
|
||||
// if (isRequiredFieldsCaptured()) {
|
||||
// updateEmployeeAPICall(index);
|
||||
// } else {
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return const MIHErrorMessage(
|
||||
// errorType: "Input Error");
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 5,
|
||||
// right: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pop(context);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.close,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 5,
|
||||
// left: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// showDeleteWarning(index);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.delete,
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
|
||||
void showDeleteWarning(int index) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHDeleteMessage(
|
||||
deleteType: "Employee",
|
||||
onTap: () {
|
||||
deleteNoteApiCall(index);
|
||||
}));
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
accessController.dispose();
|
||||
typeController.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.employees.length,
|
||||
itemBuilder: (context, index) {
|
||||
//final patient = widget.patients[index].id_no.contains(widget.searchString);
|
||||
//print(index);
|
||||
var isMe = "";
|
||||
if (widget.arguments.signedInUser.app_id ==
|
||||
widget.employees[index].app_id) {
|
||||
isMe = "(You)";
|
||||
}
|
||||
return ListTile(
|
||||
title: Text(
|
||||
"${widget.employees[index].fname} ${widget.employees[index].lname} - ${widget.employees[index].title} $isMe"),
|
||||
subtitle: Text(
|
||||
"${widget.employees[index].username}\n${widget.employees[index].email}\nAccess: ${widget.employees[index].access}",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
updateEmployeePopUp(index);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../../mih_components/mih_layout/mih_window.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../../mih_env/env.dart';
|
||||
import '../../../mih_objects/app_user.dart';
|
||||
import '../../../mih_objects/arguments.dart';
|
||||
|
||||
class BuildUserList extends StatefulWidget {
|
||||
final List<AppUser> users;
|
||||
final BusinessArguments arguments;
|
||||
|
||||
const BuildUserList({
|
||||
super.key,
|
||||
required this.users,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildUserList> createState() => _BuildUserListState();
|
||||
}
|
||||
|
||||
class _BuildUserListState extends State<BuildUserList> {
|
||||
TextEditingController accessController = TextEditingController();
|
||||
TextEditingController typeController = TextEditingController();
|
||||
TextEditingController fnameController = TextEditingController();
|
||||
TextEditingController lnameController = TextEditingController();
|
||||
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
Future<void> createBusinessUserAPICall(int index) async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
var response = await http.post(
|
||||
Uri.parse("$baseAPI/business-user/insert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": widget.arguments.business!.business_id,
|
||||
"app_id": widget.users[index].app_id,
|
||||
"signature": "",
|
||||
"sig_path": "",
|
||||
"title": typeController.text,
|
||||
"access": accessController.text,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 201) {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed(
|
||||
'/business-profile/manage',
|
||||
arguments: BusinessArguments(
|
||||
widget.arguments.signedInUser,
|
||||
widget.arguments.businessUser,
|
||||
widget.arguments.business,
|
||||
),
|
||||
);
|
||||
String message =
|
||||
"${widget.users[index].username} is now apart of your team with ${accessController.text} access to ${widget.arguments.business!.Name}";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
bool isRequiredFieldsCaptured() {
|
||||
if (accessController.text.isEmpty || typeController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
String hideEmail(String email) {
|
||||
var firstLetter = email[0];
|
||||
var end = email.split("@")[1];
|
||||
return "$firstLetter********@$end";
|
||||
}
|
||||
|
||||
void addEmployeePopUp(int index) {
|
||||
setState(() {
|
||||
//accessController.text = widget.users[index].access;
|
||||
//typeController.text = widget.users[index].title;
|
||||
// var fnameInitial = widget.users[index].fname[0];
|
||||
// var lnameInitial = widget.users[index].lname[0];
|
||||
fnameController.text = widget.users[index].username;
|
||||
lnameController.text = hideEmail(widget.users[index].email);
|
||||
});
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Add Employee",
|
||||
windowBody: [
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: fnameController,
|
||||
hintText: "Username Name",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: lnameController,
|
||||
hintText: "Email",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: typeController,
|
||||
hintText: "Title",
|
||||
dropdownOptions: const ["Doctor", "Assistant"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: accessController,
|
||||
hintText: "Access",
|
||||
dropdownOptions: const ["Full", "Partial"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
buttonText: "Add",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
onTap: () {
|
||||
if (isRequiredFieldsCaptured()) {
|
||||
createBusinessUserAPICall(index);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(
|
||||
errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
],
|
||||
windowTools: [],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
}));
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => Dialog(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// Container(
|
||||
// padding: const EdgeInsets.all(10.0),
|
||||
// width: 700.0,
|
||||
// //height: 475.0,
|
||||
// decoration: BoxDecoration(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
// borderRadius: BorderRadius.circular(25.0),
|
||||
// border: Border.all(
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// width: 5.0),
|
||||
// ),
|
||||
// child: SingleChildScrollView(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Add Employee",
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// fontSize: 35.0,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 25.0),
|
||||
// MIHTextField(
|
||||
// controller: fnameController,
|
||||
// hintText: "Username Name",
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHTextField(
|
||||
// controller: lnameController,
|
||||
// hintText: "Email",
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHDropdownField(
|
||||
// controller: typeController,
|
||||
// hintText: "Title",
|
||||
// dropdownOptions: const ["Doctor", "Assistant"],
|
||||
// required: true,
|
||||
// editable: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHDropdownField(
|
||||
// controller: accessController,
|
||||
// hintText: "Access",
|
||||
// dropdownOptions: const ["Full", "Partial"],
|
||||
// required: true,
|
||||
// editable: true,
|
||||
// ),
|
||||
// const SizedBox(height: 30.0),
|
||||
// SizedBox(
|
||||
// width: 300,
|
||||
// height: 50,
|
||||
// child: MIHButton(
|
||||
// buttonText: "Add",
|
||||
// buttonColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// textColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .primaryColor(),
|
||||
// onTap: () {
|
||||
// if (isRequiredFieldsCaptured()) {
|
||||
// createBusinessUserAPICall(index);
|
||||
// } else {
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return const MIHErrorMessage(
|
||||
// errorType: "Input Error");
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 5,
|
||||
// right: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pop(context);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.close,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
accessController.dispose();
|
||||
typeController.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.users.length,
|
||||
itemBuilder: (context, index) {
|
||||
var isYou = "";
|
||||
if (widget.arguments.signedInUser.app_id ==
|
||||
widget.users[index].app_id) {
|
||||
isYou = "(You)";
|
||||
}
|
||||
return ListTile(
|
||||
title: Text("@${widget.users[index].username} $isYou"),
|
||||
subtitle: Text(
|
||||
"Email: ${hideEmail(widget.users[index].email)}",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
addEmployeePopUp(index);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
538
Frontend/lib/mih_packages/manage_business/business_about.dart
Normal file
538
Frontend/lib/mih_packages/manage_business/business_about.dart
Normal file
@@ -0,0 +1,538 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
import 'package:http/http.dart' as http2;
|
||||
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_file_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
|
||||
class BusinessAbout extends StatefulWidget {
|
||||
final BusinessArguments arguments;
|
||||
const BusinessAbout({
|
||||
super.key,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BusinessAbout> createState() => _BusinessAboutState();
|
||||
}
|
||||
|
||||
class BusinessUserScreenArguments {}
|
||||
|
||||
class _BusinessAboutState extends State<BusinessAbout> {
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
final nameController = TextEditingController();
|
||||
final typeController = TextEditingController();
|
||||
final regController = TextEditingController();
|
||||
final logonameController = TextEditingController();
|
||||
final fnameController = TextEditingController();
|
||||
final lnameController = TextEditingController();
|
||||
final titleController = TextEditingController();
|
||||
final signtureController = TextEditingController();
|
||||
final accessController = TextEditingController();
|
||||
final contactController = TextEditingController();
|
||||
final emailController = TextEditingController();
|
||||
|
||||
late PlatformFile? selectedLogo = null;
|
||||
late PlatformFile? selectedSignature = null;
|
||||
|
||||
// late Future<BusinessUser?> futureBusinessUser;
|
||||
// BusinessUser? businessUser;
|
||||
// late Future<Business?> futureBusiness;
|
||||
// Business? business;
|
||||
|
||||
late String business_id;
|
||||
late String oldLogoPath;
|
||||
late String oldSigPath;
|
||||
|
||||
Future<void> deleteFileApiCall(String filePath) async {
|
||||
// delete file from minio
|
||||
var response = await http.delete(
|
||||
Uri.parse("$baseAPI/minio/delete/file/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{"file_path": filePath}),
|
||||
);
|
||||
//print("Here4");
|
||||
//print(response.statusCode);
|
||||
if (response.statusCode == 200) {
|
||||
//SQL delete
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
// Future<BusinessUser?> getBusinessUserDetails() async {
|
||||
// var response = await http
|
||||
// .get(Uri.parse("$baseAPI/business-user/${widget.signedInUser.app_id}"));
|
||||
// if (response.statusCode == 200) {
|
||||
// String body = response.body;
|
||||
// var decodedData = jsonDecode(body);
|
||||
// BusinessUser business_User = BusinessUser.fromJson(decodedData);
|
||||
// return business_User;
|
||||
// } else {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<Business?> getBusinessAbout() async {
|
||||
// var response = await http.get(
|
||||
// Uri.parse("$baseAPI/business/app_id/${widget.signedInUser.app_id}"));
|
||||
// if (response.statusCode == 200) {
|
||||
// String body = response.body;
|
||||
// var decodedData = jsonDecode(body);
|
||||
// Business business = Business.fromJson(decodedData);
|
||||
// return business;
|
||||
// } else {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<void> uploadSelectedFile(
|
||||
PlatformFile? file, TextEditingController controller) async {
|
||||
//to-do delete file when changed
|
||||
|
||||
var token = await SuperTokens.getAccessToken();
|
||||
//print(t);
|
||||
//print("here1");
|
||||
var request = http2.MultipartRequest(
|
||||
'POST', Uri.parse("${AppEnviroment.baseApiUrl}/minio/upload/file/"));
|
||||
request.headers['accept'] = 'application/json';
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['Content-Type'] = 'multipart/form-data';
|
||||
request.fields['app_id'] = widget.arguments.signedInUser.app_id;
|
||||
request.fields['folder'] = "business_files";
|
||||
request.files.add(await http2.MultipartFile.fromBytes('file', file!.bytes!,
|
||||
filename: file.name.replaceAll(RegExp(r' '), '-')));
|
||||
var response1 = await request.send();
|
||||
if (response1.statusCode == 200) {
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateBusinessUserAPICall(String business_id) async {
|
||||
var response = await http.put(
|
||||
Uri.parse("$baseAPI/business-user/update/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": business_id,
|
||||
"app_id": widget.arguments.signedInUser.app_id,
|
||||
"signature": signtureController.text,
|
||||
"sig_path":
|
||||
"${widget.arguments.signedInUser.app_id}/business_files/${signtureController.text}",
|
||||
"title": titleController.text,
|
||||
"access": accessController.text,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
if (selectedSignature != null) {
|
||||
uploadSelectedFile(selectedSignature, signtureController);
|
||||
deleteFileApiCall(oldSigPath);
|
||||
}
|
||||
|
||||
Navigator.of(context).pushNamed('/');
|
||||
String message =
|
||||
"Your business profile is now live! You can now start connecting with customers and growing your business.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateBusinessProfileAPICall(String business_id) async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
var response = await http.put(
|
||||
Uri.parse("$baseAPI/business/update/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": business_id,
|
||||
"Name": nameController.text,
|
||||
"type": typeController.text,
|
||||
"registration_no": regController.text,
|
||||
"logo_name": logonameController.text,
|
||||
"logo_path":
|
||||
"${widget.arguments.signedInUser.app_id}/business_files/${logonameController.text}",
|
||||
"contact_no": contactController.text,
|
||||
"bus_email": emailController.text,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
//var businessResponse = jsonDecode(response.body);
|
||||
//print(selectedLogo != null);
|
||||
if (selectedLogo != null) {
|
||||
uploadSelectedFile(selectedLogo, logonameController);
|
||||
deleteFileApiCall(oldLogoPath);
|
||||
}
|
||||
updateBusinessUserAPICall(business_id);
|
||||
} 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,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool isFieldsFilled() {
|
||||
if (nameController.text.isEmpty ||
|
||||
typeController.text.isEmpty ||
|
||||
regController.text.isEmpty ||
|
||||
logonameController.text.isEmpty ||
|
||||
fnameController.text.isEmpty ||
|
||||
lnameController.text.isEmpty ||
|
||||
titleController.text.isEmpty ||
|
||||
signtureController.text.isEmpty ||
|
||||
accessController.text.isEmpty ||
|
||||
contactController.text.isEmpty ||
|
||||
emailController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void submitForm(String business_id) {
|
||||
if (!validEmail()) {
|
||||
emailError();
|
||||
} else if (isFieldsFilled()) {
|
||||
updateBusinessProfileAPICall(business_id);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void emailError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Invalid Email");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool validEmail() {
|
||||
String text = emailController.text;
|
||||
var regex = RegExp(r'^[a-zA-Z0-9]+@[a-zA-Z.-]+\.[a-zA-Z]{2,}$');
|
||||
return regex.hasMatch(text);
|
||||
}
|
||||
|
||||
bool isFullAccess() {
|
||||
if (widget.arguments.businessUser!.access == "Partial") {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
nameController.dispose();
|
||||
typeController.dispose();
|
||||
regController.dispose();
|
||||
logonameController.dispose();
|
||||
fnameController.dispose();
|
||||
lnameController.dispose();
|
||||
titleController.dispose();
|
||||
signtureController.dispose();
|
||||
accessController.dispose();
|
||||
contactController.dispose();
|
||||
emailController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
setState(() {
|
||||
//businessUser = results;
|
||||
titleController.text = widget.arguments.businessUser!.title;
|
||||
fnameController.text = widget.arguments.signedInUser.fname;
|
||||
lnameController.text = widget.arguments.signedInUser.lname;
|
||||
signtureController.text = widget.arguments.businessUser!.signature;
|
||||
titleController.text = widget.arguments.businessUser!.title;
|
||||
accessController.text = widget.arguments.businessUser!.access;
|
||||
|
||||
oldSigPath = widget.arguments.businessUser!.sig_path;
|
||||
|
||||
//business = results;
|
||||
business_id = widget.arguments.business!.business_id;
|
||||
regController.text = widget.arguments.business!.registration_no;
|
||||
nameController.text = widget.arguments.business!.Name;
|
||||
typeController.text = widget.arguments.business!.type;
|
||||
logonameController.text = widget.arguments.business!.logo_name;
|
||||
oldLogoPath = widget.arguments.business!.logo_path;
|
||||
contactController.text = widget.arguments.business!.contact_no;
|
||||
emailController.text = widget.arguments.business!.bus_email;
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
child: KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
//print(business_id);
|
||||
submitForm(business_id);
|
||||
}
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Visibility(
|
||||
visible: isFullAccess(),
|
||||
child: Column(
|
||||
children: [
|
||||
const Text(
|
||||
"Business Profile",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: MzanziInnovationHub.of(context)
|
||||
?.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: regController,
|
||||
hintText: "Registration No.",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: nameController,
|
||||
hintText: "Business Name",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: typeController,
|
||||
hintText: "Business Type",
|
||||
dropdownOptions: const ["Doctors Office", "Other"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: contactController,
|
||||
hintText: "Contact Number",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: emailController,
|
||||
hintText: "Email",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHFileField(
|
||||
controller: logonameController,
|
||||
hintText: "Logo",
|
||||
editable: false,
|
||||
required: true,
|
||||
onPressed: () async {
|
||||
FilePickerResult? result =
|
||||
await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png', 'pdf'],
|
||||
);
|
||||
if (result == null) return;
|
||||
final selectedFile = result.files.first;
|
||||
setState(() {
|
||||
selectedLogo = selectedFile;
|
||||
});
|
||||
setState(() {
|
||||
logonameController.text = selectedFile.name;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
//const SizedBox(height: 15.0),
|
||||
const Text(
|
||||
"My Business User",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)?.theme.secondaryColor(),
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: titleController,
|
||||
hintText: "Title",
|
||||
dropdownOptions: const ["Doctor", "Assistant"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: fnameController,
|
||||
hintText: "Name",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: lnameController,
|
||||
hintText: "Surname",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHFileField(
|
||||
controller: signtureController,
|
||||
hintText: "Signature",
|
||||
editable: false,
|
||||
required: true,
|
||||
onPressed: () async {
|
||||
FilePickerResult? result =
|
||||
await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png', 'pdf'],
|
||||
);
|
||||
if (result == null) return;
|
||||
final selectedFile = result.files.first;
|
||||
setState(() {
|
||||
selectedSignature = selectedFile;
|
||||
});
|
||||
setState(() {
|
||||
signtureController.text = selectedFile.name;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
MIHDropdownField(
|
||||
controller: accessController,
|
||||
hintText: "Access",
|
||||
dropdownOptions: const ["Full", "Partial"],
|
||||
required: true,
|
||||
editable: false,
|
||||
),
|
||||
// const SizedBox(height: 15.0),
|
||||
// const Text(
|
||||
// "My Test Data",
|
||||
// style: TextStyle(
|
||||
// fontWeight: FontWeight.bold,
|
||||
// fontSize: 25,
|
||||
// ),
|
||||
// ),
|
||||
// Divider(
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)?.theme.secondaryColor(),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHTextField(
|
||||
// controller: typeController,
|
||||
// hintText: widget.arguments.business!.type,
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 15.0),
|
||||
// MIHTextField(
|
||||
// controller: titleController,
|
||||
// hintText: widget.arguments.businessUser!.title,
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 15.0),
|
||||
// MIHTextField(
|
||||
// controller: accessController,
|
||||
// hintText: widget.arguments.businessUser!.access,
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
//const SizedBox(height: 15.0),
|
||||
const SizedBox(height: 30.0),
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Update",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
onTap: () {
|
||||
//print(business_id);
|
||||
submitForm(business_id);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
578
Frontend/lib/mih_packages/manage_business/business_details.dart
Normal file
578
Frontend/lib/mih_packages/manage_business/business_details.dart
Normal file
@@ -0,0 +1,578 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
import 'package:http/http.dart' as http2;
|
||||
|
||||
import '../../mih_apis/mih_location_api.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_file_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
|
||||
class BusinessDetails extends StatefulWidget {
|
||||
final BusinessArguments arguments;
|
||||
const BusinessDetails({
|
||||
super.key,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BusinessDetails> createState() => _BusinessDetailsState();
|
||||
}
|
||||
|
||||
class BusinessUserScreenArguments {}
|
||||
|
||||
class _BusinessDetailsState extends State<BusinessDetails> {
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
final nameController = TextEditingController();
|
||||
final typeController = TextEditingController();
|
||||
final regController = TextEditingController();
|
||||
final logonameController = TextEditingController();
|
||||
final fnameController = TextEditingController();
|
||||
final lnameController = TextEditingController();
|
||||
final titleController = TextEditingController();
|
||||
final signtureController = TextEditingController();
|
||||
final accessController = TextEditingController();
|
||||
final contactController = TextEditingController();
|
||||
final emailController = TextEditingController();
|
||||
final locationController = TextEditingController();
|
||||
|
||||
late PlatformFile? selectedLogo = null;
|
||||
late PlatformFile? selectedSignature = null;
|
||||
|
||||
// late Future<BusinessUser?> futureBusinessUser;
|
||||
// BusinessUser? businessUser;
|
||||
// late Future<Business?> futureBusiness;
|
||||
// Business? business;
|
||||
|
||||
late String business_id;
|
||||
late String oldLogoPath;
|
||||
late String oldSigPath;
|
||||
|
||||
Future<void> deleteFileApiCall(String filePath) async {
|
||||
// delete file from minio
|
||||
var response = await http.delete(
|
||||
Uri.parse("$baseAPI/minio/delete/file/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{"file_path": filePath}),
|
||||
);
|
||||
//print("Here4");
|
||||
//print(response.statusCode);
|
||||
if (response.statusCode == 200) {
|
||||
//SQL delete
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
// Future<BusinessUser?> getBusinessUserDetails() async {
|
||||
// var response = await http
|
||||
// .get(Uri.parse("$baseAPI/business-user/${widget.signedInUser.app_id}"));
|
||||
// if (response.statusCode == 200) {
|
||||
// String body = response.body;
|
||||
// var decodedData = jsonDecode(body);
|
||||
// BusinessUser business_User = BusinessUser.fromJson(decodedData);
|
||||
// return business_User;
|
||||
// } else {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<Business?> getBusinessDetails() async {
|
||||
// var response = await http.get(
|
||||
// Uri.parse("$baseAPI/business/app_id/${widget.signedInUser.app_id}"));
|
||||
// if (response.statusCode == 200) {
|
||||
// String body = response.body;
|
||||
// var decodedData = jsonDecode(body);
|
||||
// Business business = Business.fromJson(decodedData);
|
||||
// return business;
|
||||
// } else {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<void> uploadSelectedFile(
|
||||
PlatformFile? file, TextEditingController controller) async {
|
||||
//to-do delete file when changed
|
||||
|
||||
var token = await SuperTokens.getAccessToken();
|
||||
//print(t);
|
||||
//print("here1");
|
||||
var request = http2.MultipartRequest(
|
||||
'POST', Uri.parse("${AppEnviroment.baseApiUrl}/minio/upload/file/"));
|
||||
request.headers['accept'] = 'application/json';
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['Content-Type'] = 'multipart/form-data';
|
||||
request.fields['app_id'] = widget.arguments.signedInUser.app_id;
|
||||
request.fields['folder'] = "business_files";
|
||||
request.files.add(await http2.MultipartFile.fromBytes('file', file!.bytes!,
|
||||
filename: file.name.replaceAll(RegExp(r' '), '-')));
|
||||
var response1 = await request.send();
|
||||
if (response1.statusCode == 200) {
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateBusinessUserAPICall(String business_id) async {
|
||||
var response = await http.put(
|
||||
Uri.parse("$baseAPI/business-user/update/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": business_id,
|
||||
"app_id": widget.arguments.signedInUser.app_id,
|
||||
"signature": signtureController.text,
|
||||
"sig_path":
|
||||
"${widget.arguments.signedInUser.app_id}/business_files/${signtureController.text}",
|
||||
"title": titleController.text,
|
||||
"access": accessController.text,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
if (selectedSignature != null) {
|
||||
uploadSelectedFile(selectedSignature, signtureController);
|
||||
deleteFileApiCall(oldSigPath);
|
||||
}
|
||||
|
||||
Navigator.of(context).pushNamed('/');
|
||||
String message =
|
||||
"Your business profile is now live! You can now start connecting with customers and growing your business.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateBusinessProfileAPICall(String business_id) async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
var response = await http.put(
|
||||
Uri.parse("$baseAPI/business/update/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": business_id,
|
||||
"Name": nameController.text,
|
||||
"type": typeController.text,
|
||||
"registration_no": regController.text,
|
||||
"logo_name": logonameController.text,
|
||||
"logo_path":
|
||||
"${widget.arguments.signedInUser.app_id}/business_files/${logonameController.text}",
|
||||
"contact_no": contactController.text,
|
||||
"bus_email": emailController.text,
|
||||
"gps_location": locationController.text,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
//var businessResponse = jsonDecode(response.body);
|
||||
//print(selectedLogo != null);
|
||||
if (selectedLogo != null) {
|
||||
uploadSelectedFile(selectedLogo, logonameController);
|
||||
deleteFileApiCall(oldLogoPath);
|
||||
}
|
||||
updateBusinessUserAPICall(business_id);
|
||||
} 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,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool isFieldsFilled() {
|
||||
if (nameController.text.isEmpty ||
|
||||
typeController.text.isEmpty ||
|
||||
regController.text.isEmpty ||
|
||||
logonameController.text.isEmpty ||
|
||||
fnameController.text.isEmpty ||
|
||||
lnameController.text.isEmpty ||
|
||||
titleController.text.isEmpty ||
|
||||
signtureController.text.isEmpty ||
|
||||
accessController.text.isEmpty ||
|
||||
contactController.text.isEmpty ||
|
||||
emailController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void submitForm(String business_id) {
|
||||
if (!validEmail()) {
|
||||
emailError();
|
||||
} else if (isFieldsFilled()) {
|
||||
updateBusinessProfileAPICall(business_id);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void emailError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Invalid Email");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool validEmail() {
|
||||
String text = emailController.text;
|
||||
var regex = RegExp(r'^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$');
|
||||
return regex.hasMatch(text);
|
||||
}
|
||||
|
||||
bool isFullAccess() {
|
||||
if (widget.arguments.businessUser!.access == "Partial") {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
nameController.dispose();
|
||||
typeController.dispose();
|
||||
regController.dispose();
|
||||
logonameController.dispose();
|
||||
fnameController.dispose();
|
||||
lnameController.dispose();
|
||||
titleController.dispose();
|
||||
signtureController.dispose();
|
||||
accessController.dispose();
|
||||
contactController.dispose();
|
||||
emailController.dispose();
|
||||
locationController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
setState(() {
|
||||
//businessUser = results;
|
||||
titleController.text = widget.arguments.businessUser!.title;
|
||||
fnameController.text = widget.arguments.signedInUser.fname;
|
||||
lnameController.text = widget.arguments.signedInUser.lname;
|
||||
signtureController.text = widget.arguments.businessUser!.signature;
|
||||
titleController.text = widget.arguments.businessUser!.title;
|
||||
accessController.text = widget.arguments.businessUser!.access;
|
||||
|
||||
oldSigPath = widget.arguments.businessUser!.sig_path;
|
||||
|
||||
//business = results;
|
||||
business_id = widget.arguments.business!.business_id;
|
||||
regController.text = widget.arguments.business!.registration_no;
|
||||
nameController.text = widget.arguments.business!.Name;
|
||||
typeController.text = widget.arguments.business!.type;
|
||||
logonameController.text = widget.arguments.business!.logo_name;
|
||||
oldLogoPath = widget.arguments.business!.logo_path;
|
||||
contactController.text = widget.arguments.business!.contact_no;
|
||||
emailController.text = widget.arguments.business!.bus_email;
|
||||
locationController.text = widget.arguments.business!.gps_location;
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
child: KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
//print(business_id);
|
||||
submitForm(business_id);
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Visibility(
|
||||
visible: isFullAccess(),
|
||||
child: Column(
|
||||
children: [
|
||||
const Text(
|
||||
"Business Profile",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)?.theme.secondaryColor(),
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: regController,
|
||||
hintText: "Registration No.",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: nameController,
|
||||
hintText: "Business Name",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: typeController,
|
||||
hintText: "Business Type",
|
||||
dropdownOptions: const ["Doctors Office", "Other"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: contactController,
|
||||
hintText: "Contact Number",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: emailController,
|
||||
hintText: "Email",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHFileField(
|
||||
controller: logonameController,
|
||||
hintText: "Logo",
|
||||
editable: false,
|
||||
required: true,
|
||||
onPressed: () async {
|
||||
FilePickerResult? result =
|
||||
await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png', 'pdf'],
|
||||
);
|
||||
if (result == null) return;
|
||||
final selectedFile = result.files.first;
|
||||
setState(() {
|
||||
selectedLogo = selectedFile;
|
||||
});
|
||||
setState(() {
|
||||
logonameController.text = selectedFile.name;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: MIHTextField(
|
||||
controller: locationController,
|
||||
hintText: "Location",
|
||||
editable: false,
|
||||
required: false,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10.0),
|
||||
SizedBox(
|
||||
width: 80.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Set",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.primaryColor(),
|
||||
onTap: () {
|
||||
MIHLocationAPI()
|
||||
.getGPSPosition(context)
|
||||
.then((position) {
|
||||
if (position != null) {
|
||||
setState(() {
|
||||
locationController.text =
|
||||
"${position.latitude}, ${position.longitude}";
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
//const SizedBox(height: 15.0),
|
||||
const Text(
|
||||
"My Business User",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)?.theme.secondaryColor(),
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: titleController,
|
||||
hintText: "Title",
|
||||
dropdownOptions: const ["Doctor", "Assistant"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: fnameController,
|
||||
hintText: "Name",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: lnameController,
|
||||
hintText: "Surname",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHFileField(
|
||||
controller: signtureController,
|
||||
hintText: "Signature",
|
||||
editable: false,
|
||||
required: true,
|
||||
onPressed: () async {
|
||||
FilePickerResult? result =
|
||||
await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png', 'pdf'],
|
||||
);
|
||||
if (result == null) return;
|
||||
final selectedFile = result.files.first;
|
||||
setState(() {
|
||||
selectedSignature = selectedFile;
|
||||
});
|
||||
setState(() {
|
||||
signtureController.text = selectedFile.name;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
MIHDropdownField(
|
||||
controller: accessController,
|
||||
hintText: "Access",
|
||||
dropdownOptions: const ["Full", "Partial"],
|
||||
required: true,
|
||||
editable: false,
|
||||
),
|
||||
// const SizedBox(height: 15.0),
|
||||
// const Text(
|
||||
// "My Test Data",
|
||||
// style: TextStyle(
|
||||
// fontWeight: FontWeight.bold,
|
||||
// fontSize: 25,
|
||||
// ),
|
||||
// ),
|
||||
// Divider(
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)?.theme.secondaryColor(),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHTextField(
|
||||
// controller: typeController,
|
||||
// hintText: widget.arguments.business!.type,
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 15.0),
|
||||
// MIHTextField(
|
||||
// controller: titleController,
|
||||
// hintText: widget.arguments.businessUser!.title,
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 15.0),
|
||||
// MIHTextField(
|
||||
// controller: accessController,
|
||||
// hintText: widget.arguments.businessUser!.access,
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
//const SizedBox(height: 15.0),
|
||||
const SizedBox(height: 30.0),
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Update",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
onTap: () {
|
||||
//print(business_id);
|
||||
submitForm(business_id);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,538 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_swipe_detector/flutter_swipe_detector.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_search_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
import '../../mih_objects/business_employee.dart';
|
||||
import 'builder/build_employee_list.dart';
|
||||
import 'builder/build_user_list.dart';
|
||||
import 'business_details.dart';
|
||||
|
||||
class ManageBusinessProfile extends StatefulWidget {
|
||||
final BusinessArguments arguments;
|
||||
const ManageBusinessProfile({
|
||||
super.key,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ManageBusinessProfile> createState() => _ManageBusinessProfileState();
|
||||
}
|
||||
|
||||
class _ManageBusinessProfileState extends State<ManageBusinessProfile> {
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
String userSearch = "";
|
||||
String errorCode = "";
|
||||
String errorBody = "";
|
||||
int selectionIndex = 0;
|
||||
|
||||
late Future<List<BusinessEmployee>> employeeList;
|
||||
late Future<List<AppUser>> userSearchResults;
|
||||
|
||||
Future<List<BusinessEmployee>> fetchEmployees() async {
|
||||
//print("Patien manager page: $endpoint");
|
||||
final response = await http.get(Uri.parse(
|
||||
"${AppEnviroment.baseApiUrl}/business-user/employees/${widget.arguments.businessUser!.business_id}"));
|
||||
errorCode = response.statusCode.toString();
|
||||
errorBody = response.body;
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
//print("Here1");
|
||||
Iterable l = jsonDecode(response.body);
|
||||
//print("Here2");
|
||||
List<BusinessEmployee> patientQueue = List<BusinessEmployee>.from(
|
||||
l.map((model) => BusinessEmployee.fromJson(model)));
|
||||
//print("Here3");
|
||||
//print(patientQueue);
|
||||
return patientQueue;
|
||||
} else {
|
||||
throw Exception('failed to load employees');
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<AppUser>> fetchUsers(String search) async {
|
||||
//TODO
|
||||
final response = await http
|
||||
.get(Uri.parse("${AppEnviroment.baseApiUrl}/users/search/$search"));
|
||||
errorCode = response.statusCode.toString();
|
||||
errorBody = response.body;
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Iterable l = jsonDecode(response.body);
|
||||
List<AppUser> users =
|
||||
List<AppUser>.from(l.map((model) => AppUser.fromJson(model)));
|
||||
return users;
|
||||
} else {
|
||||
throw Exception('failed to load patients');
|
||||
}
|
||||
}
|
||||
|
||||
Widget employeesview() {
|
||||
return Column(mainAxisSize: MainAxisSize.max, children: [
|
||||
const Text(
|
||||
"Business Team",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder(
|
||||
future: employeeList,
|
||||
builder: (context, snapshot) {
|
||||
//print("patient Queue List ${snapshot.hasData}");
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Mihloadingcircle();
|
||||
} else if (snapshot.connectionState == ConnectionState.done) {
|
||||
//List<BusinessEmployee> employeeListResults;
|
||||
// if (searchString == "") {
|
||||
// patientQueueList = [];
|
||||
// } else {
|
||||
|
||||
// print(patientQueueList);
|
||||
// }
|
||||
|
||||
return displayEmployeeList(snapshot.requireData);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"$errorCode: Error pulling Patients Data\n${AppEnviroment.baseApiUrl}/business-user/users/${widget.arguments.businessUser!.business_id}\n$errorBody",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
Widget displayEmployeeList(List<BusinessEmployee> employeeList) {
|
||||
if (employeeList.isNotEmpty) {
|
||||
return BuildEmployeeList(
|
||||
employees: employeeList,
|
||||
arguments: widget.arguments,
|
||||
);
|
||||
}
|
||||
return Center(
|
||||
child: Text(
|
||||
"",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!.theme.messageTextColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget displayUserList(List<AppUser> userList) {
|
||||
if (userList.isNotEmpty) {
|
||||
return BuildUserList(
|
||||
users: userList,
|
||||
arguments: widget.arguments,
|
||||
);
|
||||
}
|
||||
return Center(
|
||||
child: Text(
|
||||
"Enter Username or Email to search",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!.theme.messageTextColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void submitUserForm() {
|
||||
if (searchController.text != "") {
|
||||
setState(() {
|
||||
userSearch = searchController.text;
|
||||
userSearchResults = fetchUsers(userSearch);
|
||||
});
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget userSearchView() {
|
||||
return KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
submitUserForm();
|
||||
}
|
||||
},
|
||||
child: Column(mainAxisSize: MainAxisSize.max, children: [
|
||||
const Text(
|
||||
"User Search",
|
||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||
),
|
||||
//spacer
|
||||
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
|
||||
const SizedBox(height: 10),
|
||||
MIHSearchField(
|
||||
controller: searchController,
|
||||
hintText: "Username or Email Search",
|
||||
required: true,
|
||||
editable: true,
|
||||
onTap: () {
|
||||
submitUserForm();
|
||||
},
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder(
|
||||
future: userSearchResults,
|
||||
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<AppUser> patientsList;
|
||||
if (userSearch == "") {
|
||||
patientsList = [];
|
||||
} else {
|
||||
patientsList = snapshot.data!;
|
||||
//print(patientsList);
|
||||
}
|
||||
|
||||
return displayUserList(patientsList);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"$errorCode: Error pulling Patients Data\n/patients/search/$userSearch\n$errorBody",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
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 emailError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Invalid Email");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget showSelection(int selectionIndex) {
|
||||
// if (selectionIndex == 0) {
|
||||
// return BusinessDetails(arguments: widget.arguments);
|
||||
// } else
|
||||
if (selectionIndex == 0) {
|
||||
return BusinessDetails(arguments: widget.arguments);
|
||||
} else if (selectionIndex == 1) {
|
||||
return employeesview();
|
||||
} else {
|
||||
return userSearchView();
|
||||
}
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
Navigator.of(context).popAndPushNamed(
|
||||
'/',
|
||||
arguments: false,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
bool isFullAccess = false;
|
||||
if (widget.arguments.businessUser!.access == "Full") {
|
||||
isFullAccess = true;
|
||||
}
|
||||
return MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.end,
|
||||
headerItems: [
|
||||
// IconButton(
|
||||
// onPressed: () {
|
||||
// setState(() {
|
||||
// selectionIndex = 0;
|
||||
// });
|
||||
// },
|
||||
// icon: const Icon(
|
||||
// Icons.info_outline,
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
//============ Business Details ================
|
||||
Visibility(
|
||||
visible: selectionIndex != 0,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
selectionIndex = 0;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.business,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: selectionIndex == 0,
|
||||
child: IconButton.filled(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
selectionIndex = 0;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.business,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
//============ Team Manager ================
|
||||
Visibility(
|
||||
visible: isFullAccess && selectionIndex != 1,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
selectionIndex = 1;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.people_outline,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: isFullAccess && selectionIndex == 1,
|
||||
child: IconButton.filled(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
selectionIndex = 1;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.people_outline,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
//============ Add Team member ================
|
||||
Visibility(
|
||||
visible: isFullAccess && selectionIndex != 2,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
selectionIndex = 2;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: isFullAccess && selectionIndex == 2,
|
||||
child: IconButton.filled(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
selectionIndex = 2;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: true,
|
||||
bodyItems: [
|
||||
showSelection(selectionIndex),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
searchController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
userSearchResults = fetchUsers("abc");
|
||||
employeeList = fetchEmployees();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SwipeDetector(
|
||||
onSwipeLeft: (offset) {
|
||||
if (selectionIndex < 2) {
|
||||
setState(() {
|
||||
selectionIndex += 1;
|
||||
});
|
||||
}
|
||||
//print("swipe left");
|
||||
},
|
||||
onSwipeRight: (offset) {
|
||||
if (selectionIndex > 0) {
|
||||
setState(() {
|
||||
selectionIndex -= 1;
|
||||
});
|
||||
}
|
||||
//print("swipe right");
|
||||
},
|
||||
child: MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
secondaryActionButton: null,
|
||||
header: getHeader(),
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
),
|
||||
);
|
||||
// return Scaffold(
|
||||
// // appBar: const MIHAppBar(
|
||||
// // barTitle: "Business Profile",
|
||||
// // propicFile: null,
|
||||
// // ),
|
||||
// //drawer: MIHAppDrawer(signedInUser: widget.arguments.signedInUser),
|
||||
// body: SafeArea(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// SingleChildScrollView(
|
||||
// padding: const EdgeInsets.all(15),
|
||||
// child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// mainAxisSize: MainAxisSize.max,
|
||||
// children: [
|
||||
// //const SizedBox(height: 20),
|
||||
// SizedBox(
|
||||
// width: screenWidth,
|
||||
// child: Row(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// crossAxisAlignment: CrossAxisAlignment.end,
|
||||
// mainAxisAlignment: MainAxisAlignment.end,
|
||||
// children: [
|
||||
// IconButton(
|
||||
// onPressed: () {
|
||||
// setState(() {
|
||||
// selectionIndex = 0;
|
||||
// });
|
||||
// },
|
||||
// icon: const Icon(
|
||||
// Icons.people_outline,
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// IconButton(
|
||||
// onPressed: () {
|
||||
// setState(() {
|
||||
// selectionIndex = 1;
|
||||
// });
|
||||
// },
|
||||
// icon: const Icon(
|
||||
// Icons.add,
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// showSelection(selectionIndex, screenWidth, screenHeight),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 10,
|
||||
// left: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// icon: const Icon(Icons.arrow_back),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,685 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:http/http.dart' as http2;
|
||||
|
||||
import '../../mih_apis/mih_location_api.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_file_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
|
||||
class ProfileBusinessAdd extends StatefulWidget {
|
||||
//final BusinessUserScreenArguments arguments;
|
||||
final AppUser signedInUser;
|
||||
const ProfileBusinessAdd({
|
||||
super.key,
|
||||
required this.signedInUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ProfileBusinessAdd> createState() => _ProfileBusinessAddState();
|
||||
}
|
||||
|
||||
class _ProfileBusinessAddState extends State<ProfileBusinessAdd> {
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
final nameController = TextEditingController();
|
||||
final typeController = TextEditingController();
|
||||
final regController = TextEditingController();
|
||||
final addressController = TextEditingController();
|
||||
final logonameController = TextEditingController();
|
||||
final fnameController = TextEditingController();
|
||||
final lnameController = TextEditingController();
|
||||
final titleController = TextEditingController();
|
||||
final signtureController = TextEditingController();
|
||||
final accessController = TextEditingController();
|
||||
final contactController = TextEditingController();
|
||||
final emailController = TextEditingController();
|
||||
final locationController = TextEditingController();
|
||||
|
||||
late PlatformFile selectedLogo;
|
||||
late PlatformFile selectedSignature;
|
||||
|
||||
Future<void> uploadSelectedFile(
|
||||
PlatformFile file, TextEditingController controller) async {
|
||||
var token = await SuperTokens.getAccessToken();
|
||||
var request = http2.MultipartRequest(
|
||||
'POST', Uri.parse("${AppEnviroment.baseApiUrl}/minio/upload/file/"));
|
||||
request.headers['accept'] = 'application/json';
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['Content-Type'] = 'multipart/form-data';
|
||||
request.fields['app_id'] = widget.signedInUser.app_id;
|
||||
request.fields['folder'] = "business_files";
|
||||
request.files.add(await http2.MultipartFile.fromBytes('file', file.bytes!,
|
||||
filename: file.name.replaceAll(RegExp(r' '), '-')));
|
||||
var response1 = await request.send();
|
||||
if (response1.statusCode == 200) {
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> createBusinessUserAPICall(String business_id) async {
|
||||
var response = await http.post(
|
||||
Uri.parse("$baseAPI/business-user/insert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": business_id,
|
||||
"app_id": widget.signedInUser.app_id,
|
||||
"signature": signtureController.text,
|
||||
"sig_path":
|
||||
"${widget.signedInUser.app_id}/business_files/${signtureController.text}",
|
||||
"title": titleController.text,
|
||||
"access": accessController.text,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 201) {
|
||||
uploadSelectedFile(selectedSignature, signtureController);
|
||||
Navigator.of(context).pushNamed('/');
|
||||
String message =
|
||||
"Your business profile is now live! You can now start connecting with customers and growing your business.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> createBusinessProfileAPICall() async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse("$baseAPI/business/insert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"Name": nameController.text,
|
||||
"type": typeController.text,
|
||||
"registration_no": regController.text,
|
||||
"logo_name": logonameController.text,
|
||||
"logo_path":
|
||||
"${widget.signedInUser.app_id}/business_files/${logonameController.text}",
|
||||
"contact_no": contactController.text,
|
||||
"bus_email": emailController.text,
|
||||
"gps_location": locationController.text,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 201) {
|
||||
var businessResponse = jsonDecode(response.body);
|
||||
createBusinessUserAPICall(businessResponse['business_id']);
|
||||
uploadSelectedFile(selectedLogo, logonameController);
|
||||
} 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,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool isFieldsFilled() {
|
||||
if (nameController.text.isEmpty ||
|
||||
typeController.text.isEmpty ||
|
||||
regController.text.isEmpty ||
|
||||
logonameController.text.isEmpty ||
|
||||
fnameController.text.isEmpty ||
|
||||
lnameController.text.isEmpty ||
|
||||
titleController.text.isEmpty ||
|
||||
signtureController.text.isEmpty ||
|
||||
accessController.text.isEmpty ||
|
||||
contactController.text.isEmpty ||
|
||||
emailController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void submitForm() {
|
||||
if (!validEmail()) {
|
||||
emailError();
|
||||
} else if (isFieldsFilled()) {
|
||||
createBusinessProfileAPICall();
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void emailError() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Invalid Email");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool validEmail() {
|
||||
String text = emailController.text;
|
||||
var regex = RegExp(r'^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$');
|
||||
return regex.hasMatch(text);
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"Add Business Profile",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: true,
|
||||
bodyItems: [
|
||||
KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
submitForm();
|
||||
}
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
//const SizedBox(height: 15),
|
||||
const Text(
|
||||
"My Business Details",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor()),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: regController,
|
||||
hintText: "Registration No.",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: nameController,
|
||||
hintText: "Business Name",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: typeController,
|
||||
hintText: "Business Type",
|
||||
dropdownOptions: const ["Doctors Office", "Other"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: contactController,
|
||||
hintText: "Contact Number",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: emailController,
|
||||
hintText: "Email",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHFileField(
|
||||
controller: logonameController,
|
||||
hintText: "Logo",
|
||||
editable: false,
|
||||
required: true,
|
||||
onPressed: () async {
|
||||
FilePickerResult? result =
|
||||
await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png', 'pdf'],
|
||||
);
|
||||
if (result == null) return;
|
||||
final selectedFile = result.files.first;
|
||||
setState(() {
|
||||
selectedLogo = selectedFile;
|
||||
});
|
||||
setState(() {
|
||||
logonameController.text = selectedFile.name;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: MIHTextField(
|
||||
controller: locationController,
|
||||
hintText: "Location",
|
||||
editable: false,
|
||||
required: false,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10.0),
|
||||
SizedBox(
|
||||
width: 80.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Set",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.primaryColor(),
|
||||
onTap: () {
|
||||
MIHLocationAPI()
|
||||
.getGPSPosition(context)
|
||||
.then((position) {
|
||||
if (position != null) {
|
||||
setState(() {
|
||||
locationController.text =
|
||||
"${position.latitude}, ${position.longitude}";
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 15.0),
|
||||
Divider(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)?.theme.secondaryColor(),
|
||||
),
|
||||
//const SizedBox(height: 15.0),
|
||||
const Text(
|
||||
"My Business User",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22,
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor()),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: titleController,
|
||||
hintText: "Title",
|
||||
dropdownOptions: const ["Doctor", "Assistant"],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: fnameController,
|
||||
hintText: "Name",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: lnameController,
|
||||
hintText: "Surname",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHFileField(
|
||||
controller: signtureController,
|
||||
hintText: "Signature",
|
||||
editable: false,
|
||||
required: true,
|
||||
onPressed: () async {
|
||||
FilePickerResult? result =
|
||||
await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png', 'pdf'],
|
||||
);
|
||||
if (result == null) return;
|
||||
final selectedFile = result.files.first;
|
||||
setState(() {
|
||||
selectedSignature = selectedFile;
|
||||
});
|
||||
setState(() {
|
||||
signtureController.text = selectedFile.name;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
MIHDropdownField(
|
||||
controller: accessController,
|
||||
hintText: "Access",
|
||||
dropdownOptions: const ["Full", "Partial"],
|
||||
required: true,
|
||||
editable: false,
|
||||
),
|
||||
const SizedBox(height: 30.0),
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Add",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
onTap: () {
|
||||
submitForm();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
nameController.dispose();
|
||||
typeController.dispose();
|
||||
regController.dispose();
|
||||
logonameController.dispose();
|
||||
fnameController.dispose();
|
||||
lnameController.dispose();
|
||||
titleController.dispose();
|
||||
signtureController.dispose();
|
||||
accessController.dispose();
|
||||
contactController.dispose();
|
||||
emailController.dispose();
|
||||
locationController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
setState(() {
|
||||
fnameController.text = widget.signedInUser.fname;
|
||||
lnameController.text = widget.signedInUser.lname;
|
||||
accessController.text = "Full";
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
secondaryActionButton: null,
|
||||
header: getHeader(),
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
|
||||
// return Scaffold(
|
||||
// // appBar: const MIHAppBar(
|
||||
// // barTitle: "Add Business",
|
||||
// // propicFile: null,
|
||||
// // ),
|
||||
// //drawer: MIHAppDrawer(signedInUser: widget.signedInUser),
|
||||
// body: SafeArea(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// KeyboardListener(
|
||||
// focusNode: _focusNode,
|
||||
// autofocus: true,
|
||||
// onKeyEvent: (event) async {
|
||||
// if (event is KeyDownEvent &&
|
||||
// event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
// submitForm();
|
||||
// }
|
||||
// },
|
||||
// child: SingleChildScrollView(
|
||||
// padding: const EdgeInsets.all(15),
|
||||
// child: Column(
|
||||
// children: [
|
||||
// //const SizedBox(height: 15),
|
||||
// const Text(
|
||||
// "Add Business Profile",
|
||||
// style: TextStyle(
|
||||
// fontWeight: FontWeight.bold,
|
||||
// fontSize: 25,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 25.0),
|
||||
// MIHTextField(
|
||||
// controller: regController,
|
||||
// hintText: "Registration No.",
|
||||
// editable: true,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHTextField(
|
||||
// controller: nameController,
|
||||
// hintText: "Business Name",
|
||||
// editable: true,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHDropdownField(
|
||||
// controller: typeController,
|
||||
// hintText: "Business Type",
|
||||
// dropdownOptions: const ["Doctors Office", "Other"],
|
||||
// required: true,
|
||||
// editable: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHTextField(
|
||||
// controller: contactController,
|
||||
// hintText: "Contact Number",
|
||||
// editable: true,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHTextField(
|
||||
// controller: emailController,
|
||||
// hintText: "Email",
|
||||
// editable: true,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHFileField(
|
||||
// controller: logonameController,
|
||||
// hintText: "Logo",
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// onPressed: () async {
|
||||
// FilePickerResult? result =
|
||||
// await FilePicker.platform.pickFiles(
|
||||
// type: FileType.custom,
|
||||
// allowedExtensions: ['jpg', 'png', 'pdf'],
|
||||
// );
|
||||
// if (result == null) return;
|
||||
// final selectedFile = result.files.first;
|
||||
// setState(() {
|
||||
// selectedLogo = selectedFile;
|
||||
// });
|
||||
// setState(() {
|
||||
// logonameController.text = selectedFile.name;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
// const SizedBox(height: 15.0),
|
||||
// Divider(
|
||||
// color: MzanziInnovationHub.of(context)
|
||||
// ?.theme
|
||||
// .secondaryColor(),
|
||||
// ),
|
||||
// //const SizedBox(height: 15.0),
|
||||
// const Text(
|
||||
// "My Business User",
|
||||
// style: TextStyle(
|
||||
// fontWeight: FontWeight.bold,
|
||||
// fontSize: 25,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 25.0),
|
||||
// MIHDropdownField(
|
||||
// controller: titleController,
|
||||
// hintText: "Title",
|
||||
// dropdownOptions: const ["Doctor", "Assistant"],
|
||||
// required: true,
|
||||
// editable: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHTextField(
|
||||
// controller: fnameController,
|
||||
// hintText: "Name",
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHTextField(
|
||||
// controller: lnameController,
|
||||
// hintText: "Surname",
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// MIHFileField(
|
||||
// controller: signtureController,
|
||||
// hintText: "Signature",
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// onPressed: () async {
|
||||
// FilePickerResult? result =
|
||||
// await FilePicker.platform.pickFiles(
|
||||
// type: FileType.custom,
|
||||
// allowedExtensions: ['jpg', 'png', 'pdf'],
|
||||
// );
|
||||
// if (result == null) return;
|
||||
// final selectedFile = result.files.first;
|
||||
// setState(() {
|
||||
// selectedSignature = selectedFile;
|
||||
// });
|
||||
// setState(() {
|
||||
// signtureController.text = selectedFile.name;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
// const SizedBox(height: 15.0),
|
||||
// MIHDropdownField(
|
||||
// controller: accessController,
|
||||
// hintText: "Access",
|
||||
// dropdownOptions: const ["Full", "Partial"],
|
||||
// required: true,
|
||||
// editable: false,
|
||||
// ),
|
||||
// const SizedBox(height: 30.0),
|
||||
// SizedBox(
|
||||
// width: 500.0,
|
||||
// height: 50.0,
|
||||
// child: MIHButton(
|
||||
// buttonText: "Add",
|
||||
// buttonColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// textColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .primaryColor(),
|
||||
// onTap: () {
|
||||
// submitForm();
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 10,
|
||||
// left: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// icon: const Icon(Icons.arrow_back),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
}
|
||||
970
Frontend/lib/mih_packages/mih_home/mih_home.dart
Normal file
970
Frontend/lib/mih_packages/mih_home/mih_home.dart
Normal file
@@ -0,0 +1,970 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_swipe_detector/flutter_swipe_detector.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:google_nav_bar/google_nav_bar.dart';
|
||||
import '../../main.dart';
|
||||
//import 'package:supertokens_flutter/http.dart' as http;
|
||||
import "package:universal_html/html.dart" as html;
|
||||
|
||||
import '../../mih_apis/mih_location_api.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_search_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_app_drawer.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_layout/mih_notification_drawer.dart';
|
||||
import '../../mih_components/mih_layout/mih_tile.dart';
|
||||
import '../../mih_components/mih_layout/mih_window.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_delete_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_notification_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_warning_message.dart';
|
||||
import '../../mih_components/mih_profile_picture.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
import '../../mih_objects/business.dart';
|
||||
import '../../mih_objects/business_user.dart';
|
||||
import '../../mih_objects/notification.dart';
|
||||
import '../test/test.dart';
|
||||
|
||||
class MIHHome extends StatefulWidget {
|
||||
final AppUser signedInUser;
|
||||
final BusinessUser? businessUser;
|
||||
final Business? business;
|
||||
final List<MIHNotification> notifications;
|
||||
final ImageProvider<Object>? propicFile;
|
||||
final bool isUserNew;
|
||||
final bool isBusinessUser;
|
||||
final bool isBusinessUserNew;
|
||||
final bool isDevActive;
|
||||
final bool personalSelected;
|
||||
const MIHHome({
|
||||
super.key,
|
||||
required this.signedInUser,
|
||||
required this.businessUser,
|
||||
required this.business,
|
||||
required this.notifications,
|
||||
required this.propicFile,
|
||||
required this.isUserNew,
|
||||
required this.isBusinessUser,
|
||||
required this.isBusinessUserNew,
|
||||
required this.isDevActive,
|
||||
required this.personalSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MIHHome> createState() => _MIHHomeState();
|
||||
}
|
||||
|
||||
class _MIHHomeState extends State<MIHHome> {
|
||||
final proPicController = TextEditingController();
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
late List<MIHTile> persHTList = [];
|
||||
late List<MIHTile> busHTList = [];
|
||||
late List<List<MIHTile>> pbswitch;
|
||||
late List<MIHNotification> notifiList;
|
||||
late bool businessUserSwitch;
|
||||
int _selectedIndex = 0;
|
||||
String appSearch = "";
|
||||
int amount = 10;
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
void setAppsNewPersonal(List<MIHTile> tileList) {
|
||||
if (widget.signedInUser.fname == "") {
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed('/user-profile',
|
||||
arguments: AppProfileUpdateArguments(
|
||||
widget.signedInUser, widget.propicFile));
|
||||
},
|
||||
tileName: "Setup Profie",
|
||||
tileIcon: Icon(
|
||||
Icons.perm_identity,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void setAppsNewBusiness(List<MIHTile> tileList) {
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).popAndPushNamed(
|
||||
'/business-profile/set-up',
|
||||
arguments: widget.signedInUser,
|
||||
);
|
||||
},
|
||||
tileName: "Setup Business",
|
||||
tileIcon: Icon(
|
||||
Icons.add_business_outlined,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
}
|
||||
|
||||
void setAppsPersonal(List<MIHTile> tileList) {
|
||||
ImageProvider logo = MzanziInnovationHub.of(context)!.theme.logoImage();
|
||||
tileList.add(MIHTile(
|
||||
videoYTLink: "https://www.youtube.com/watch?v=P2bM9eosJ_A",
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/user-profile',
|
||||
arguments:
|
||||
AppProfileUpdateArguments(widget.signedInUser, widget.propicFile),
|
||||
);
|
||||
},
|
||||
tileName: "Mzansi Profile",
|
||||
tileIcon: Padding(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: Image(image: logo),
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed('/patient-profile',
|
||||
arguments: PatientViewArguments(
|
||||
widget.signedInUser, null, null, null, "personal"));
|
||||
},
|
||||
tileName: "Patient Profile",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.bookMedical,
|
||||
color: getSec(),
|
||||
size: 200,
|
||||
),
|
||||
),
|
||||
// Icon(
|
||||
// Icons.medication,
|
||||
// color: getSec(),
|
||||
// size: 200,
|
||||
// ),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/appointments',
|
||||
arguments: widget.signedInUser,
|
||||
);
|
||||
},
|
||||
tileName: "Appointments",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.calendarDays,
|
||||
color: getSec(),
|
||||
size: 200,
|
||||
),
|
||||
),
|
||||
// Icon(
|
||||
// Icons.calendar_month,
|
||||
// color: getSec(),
|
||||
// size: 230,
|
||||
// ),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/access-review',
|
||||
arguments: widget.signedInUser,
|
||||
);
|
||||
},
|
||||
tileName: "Access",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.userCheck,
|
||||
color: getSec(),
|
||||
size: 170,
|
||||
),
|
||||
),
|
||||
// Icon(
|
||||
// Icons.check_box_outlined,
|
||||
// color: getSec(),
|
||||
// size: 200,
|
||||
// ),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/about',
|
||||
arguments: widget.signedInUser,
|
||||
);
|
||||
},
|
||||
tileName: "About MIH",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.circleInfo,
|
||||
color: getSec(),
|
||||
size: 200,
|
||||
),
|
||||
),
|
||||
// Icon(
|
||||
// Icons.info_outline,
|
||||
// color: getSec(),
|
||||
// size: 230,
|
||||
// ),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
}
|
||||
|
||||
void setAppsBusiness(List<MIHTile> tileList) {
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/business-profile/manage',
|
||||
arguments: BusinessArguments(
|
||||
widget.signedInUser,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
),
|
||||
);
|
||||
},
|
||||
tileName: "Business Profile",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.buildingUser,
|
||||
color: getSec(),
|
||||
size: 165,
|
||||
),
|
||||
),
|
||||
// Icon(
|
||||
// Icons.business,
|
||||
// color: getSec(),
|
||||
// size: 230,
|
||||
// ),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
// tileList.add(MIHTile(
|
||||
// onTap: () {
|
||||
// Navigator.of(context).pushNamed(
|
||||
// '/access-review',
|
||||
// arguments: widget.signedInUser,
|
||||
// );
|
||||
// },
|
||||
// tileName: "Access",
|
||||
// tileIcon: Icon(
|
||||
// Icons.check_box_outlined,
|
||||
// color: getSec(),
|
||||
// size: 200,
|
||||
// ),
|
||||
// p: getPrim(),
|
||||
// s: getSec(),
|
||||
// ));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/patient-manager',
|
||||
arguments: BusinessArguments(
|
||||
widget.signedInUser,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
),
|
||||
);
|
||||
},
|
||||
tileName: "Manage Patient",
|
||||
tileIcon: Center(
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.bookMedical,
|
||||
color: getSec(),
|
||||
size: 200,
|
||||
),
|
||||
),
|
||||
// Icon(
|
||||
// Icons.medication,
|
||||
// color: getSec(),
|
||||
// size: 230,
|
||||
// ),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
}
|
||||
|
||||
void setAppsDev(List<MIHTile> tileList) {
|
||||
if (AppEnviroment.getEnv() == "Dev") {
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
barrierColor: const Color(0x01000000),
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHTest();
|
||||
},
|
||||
);
|
||||
},
|
||||
tileName: "video - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.video_file,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
barrierColor: const Color(0x01000000),
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Builder(builder: (context) {
|
||||
return MIHNotificationMessage(
|
||||
arguments: NotificationArguments(
|
||||
"Testing",
|
||||
"Testing the new MIH Notification",
|
||||
() {
|
||||
Navigator.of(context).pop();
|
||||
//Scaffold.of(context).openEndDrawer();
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
tileName: "Notify - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.notifications,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
},
|
||||
tileName: "Loading - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.change_circle,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/business-profile/set-up',
|
||||
arguments: widget.signedInUser,
|
||||
);
|
||||
},
|
||||
tileName: "Setup Bus - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.add_business_outlined,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed('/patient-profile/set-up',
|
||||
arguments: widget.signedInUser);
|
||||
},
|
||||
tileName: "Add Pat - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.add_circle_outline,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
// return const MIHWarningMessage(warningType: "No Access");
|
||||
return const MIHWarningMessage(warningType: "Expired Access");
|
||||
},
|
||||
);
|
||||
},
|
||||
tileName: "Warn - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
// return const MIHErrorMessage(errorType: "Input Error");
|
||||
// return const MIHErrorMessage(errorType: "Password Requirements");
|
||||
// return const MIHErrorMessage(errorType: "Invalid Username");
|
||||
// return const MIHErrorMessage(errorType: "Invalid Email");
|
||||
// return const MIHErrorMessage(errorType: "User Exists");
|
||||
// return const MIHErrorMessage(errorType: "Password Match");
|
||||
// return const MIHErrorMessage(errorType: "Invalid Credentials");
|
||||
return const MIHErrorMessage(errorType: "Internet Connection");
|
||||
},
|
||||
);
|
||||
},
|
||||
tileName: "Error - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.error_outline_outlined,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHSuccessMessage(
|
||||
successType: "Success",
|
||||
successMessage:
|
||||
"Congratulations! Your account has been created successfully. You are log in and can start exploring.\n\nPlease note: more apps will appear once you update your profile.");
|
||||
},
|
||||
);
|
||||
},
|
||||
tileName: "Success - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.check_circle_outline_outlined,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
// return MIHDeleteMessage(deleteType: "Note", onTap: () {});
|
||||
return MIHDeleteMessage(deleteType: "File", onTap: () {});
|
||||
},
|
||||
);
|
||||
},
|
||||
tileName: "Delete - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.delete_forever_outlined,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
// return const MIHErrorMessage(errorType: "Input Error");
|
||||
// return const MIHErrorMessage(errorType: "Password Requirements");
|
||||
// return const MIHErrorMessage(errorType: "Invalid Username");
|
||||
// return const MIHErrorMessage(errorType: "Invalid Email");
|
||||
// return const MIHErrorMessage(errorType: "User Exists");
|
||||
// return const MIHErrorMessage(errorType: "Password Match");
|
||||
// return const MIHErrorMessage(errorType: "Invalid Credentials");
|
||||
return MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle:
|
||||
"Test Window title that is too large for mobile devices",
|
||||
windowBody: const [
|
||||
SizedBox(
|
||||
height: 250,
|
||||
)
|
||||
],
|
||||
windowTools: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
//deleteFilePopUp(filePath, fileID);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.delete,
|
||||
size: 35,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
//deleteFilePopUp(filePath, fileID);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.wallet,
|
||||
size: 35,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
tileName: "Window - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.window,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
tileList.add(MIHTile(
|
||||
onTap: () {
|
||||
MIHLocationAPI().getGPSPosition(context).then((position) {
|
||||
if (position != null) {
|
||||
print(position);
|
||||
print(
|
||||
"Distance: ${MIHLocationAPI().getDistanceInMeaters(position, position)}m");
|
||||
}
|
||||
});
|
||||
},
|
||||
tileName: "Location - Dev",
|
||||
tileIcon: Icon(
|
||||
Icons.location_pin,
|
||||
color: getSec(),
|
||||
size: 230,
|
||||
),
|
||||
p: getPrim(),
|
||||
s: getSec(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
List<MIHTile> searchApp(List<MIHTile> appList, String searchString) {
|
||||
if (searchString == "") {
|
||||
return appList;
|
||||
} else {
|
||||
List<MIHTile> temp = [];
|
||||
for (var item in appList) {
|
||||
if (item.tileName.toLowerCase().contains(appSearch.toLowerCase())) {
|
||||
temp.add(item);
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
List<List<MIHTile>> setApps(
|
||||
List<MIHTile> personalTileList, List<MIHTile> businessTileList) {
|
||||
if (widget.isUserNew) {
|
||||
setAppsNewPersonal(personalTileList);
|
||||
} else if (!widget.isBusinessUser) {
|
||||
setAppsPersonal(personalTileList);
|
||||
} else if (widget.isBusinessUserNew) {
|
||||
setAppsPersonal(personalTileList);
|
||||
setAppsNewBusiness(businessTileList);
|
||||
} else {
|
||||
setAppsPersonal(personalTileList);
|
||||
setAppsBusiness(businessTileList);
|
||||
}
|
||||
if (widget.isDevActive) {
|
||||
setAppsDev(personalTileList);
|
||||
setAppsDev(businessTileList);
|
||||
}
|
||||
return [personalTileList, businessTileList];
|
||||
}
|
||||
|
||||
Color getPrim() {
|
||||
return MzanziInnovationHub.of(context)!.theme.secondaryColor();
|
||||
}
|
||||
|
||||
Color getSec() {
|
||||
return MzanziInnovationHub.of(context)!.theme.primaryColor();
|
||||
}
|
||||
|
||||
bool isBusinessUser(AppUser signedInUser) {
|
||||
if (signedInUser.type == "personal") {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
String getHeading(int index) {
|
||||
if (index == 0) {
|
||||
return "Personal Apps";
|
||||
} else {
|
||||
return "Business Apps";
|
||||
}
|
||||
}
|
||||
|
||||
void onDragStart(DragStartDetails startDrag) {
|
||||
Scaffold.of(context).openDrawer();
|
||||
print(startDrag.globalPosition.dx);
|
||||
}
|
||||
|
||||
Widget getActionButton() {
|
||||
return Builder(builder: (context) {
|
||||
return MIHAction(
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.only(left: 5.0),
|
||||
child: MIHProfilePicture(
|
||||
profilePictureFile: widget.propicFile,
|
||||
proPicController: proPicController,
|
||||
proPic: null,
|
||||
width: 45,
|
||||
radius: 21,
|
||||
drawerMode: false,
|
||||
editable: false,
|
||||
onChange: (newProPic) {},
|
||||
),
|
||||
),
|
||||
// const Icon(Icons.apps),
|
||||
iconSize: 45,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
appSearch = "";
|
||||
searchController.clear();
|
||||
});
|
||||
//key.currentState.o
|
||||
Scaffold.of(context).openDrawer();
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget getSecondaryActionButton() {
|
||||
Widget notIIcon;
|
||||
if (hasNewNotifications()) {
|
||||
notIIcon = Stack(
|
||||
children: [
|
||||
const Icon(Icons.notifications),
|
||||
Positioned(
|
||||
right: 0,
|
||||
top: 0,
|
||||
child: Icon(
|
||||
Icons.circle,
|
||||
size: 10,
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
} else {
|
||||
notIIcon = const Icon(Icons.notifications);
|
||||
}
|
||||
return Builder(builder: (context) {
|
||||
return MIHAction(
|
||||
icon: notIIcon,
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
appSearch = "";
|
||||
searchController.clear();
|
||||
});
|
||||
//key.currentState.o
|
||||
Scaffold.of(context).openEndDrawer();
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"Mzanzi Innovation Hub",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody(double width, double height) {
|
||||
return MIHBody(
|
||||
borderOn: false,
|
||||
bodyItems: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 4,
|
||||
child: KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
setState(() {
|
||||
appSearch = searchController.text;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: SizedBox(
|
||||
child: MIHSearchField(
|
||||
controller: searchController,
|
||||
hintText: "Search Mzansi Apps",
|
||||
required: false,
|
||||
editable: true,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
appSearch = searchController.text;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: IconButton(
|
||||
//padding: const EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
appSearch = "";
|
||||
searchController.clear();
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.filter_alt_off,
|
||||
size: 30,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
GridView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.only(
|
||||
left: width / 10,
|
||||
right: width / 10,
|
||||
//bottom: height / 5,
|
||||
//top: 20,
|
||||
),
|
||||
// physics: ,
|
||||
// shrinkWrap: true,
|
||||
itemCount: searchApp(pbswitch[_selectedIndex], appSearch).length,
|
||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
mainAxisSpacing: 15, maxCrossAxisExtent: 200),
|
||||
itemBuilder: (context, index) {
|
||||
return searchApp(pbswitch[_selectedIndex], appSearch)[index];
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHAppDrawer getActionDrawer() {
|
||||
return MIHAppDrawer(
|
||||
signedInUser: widget.signedInUser,
|
||||
propicFile: widget.propicFile,
|
||||
);
|
||||
}
|
||||
|
||||
MIHNotificationDrawer getSecondaryActionDrawer() {
|
||||
return MIHNotificationDrawer(
|
||||
signedInUser: widget.signedInUser,
|
||||
notifications: widget.notifications,
|
||||
);
|
||||
}
|
||||
|
||||
Widget getBottomNavBar() {
|
||||
return Visibility(
|
||||
visible: isBusinessUser(widget.signedInUser),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 10.0, right: 10.0, bottom: 10.0, top: 0),
|
||||
child: GNav(
|
||||
//hoverColor: Colors.lightBlueAccent,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
iconSize: 35.0,
|
||||
activeColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
tabBackgroundColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
//gap: 20,
|
||||
//padding: EdgeInsets.all(15),
|
||||
tabs: [
|
||||
GButton(
|
||||
icon: Icons.perm_identity,
|
||||
text: "Personal",
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 0;
|
||||
});
|
||||
},
|
||||
),
|
||||
GButton(
|
||||
icon: Icons.business_center,
|
||||
text: "Business",
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 1;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
selectedIndex: _selectedIndex,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool hasNewNotifications() {
|
||||
//print(widget.notifications.toString());
|
||||
if (notifiList.map((item) => item.notification_read).contains("No")) {
|
||||
//print("New Notification Available");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
//print("No New Notification Available");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> refreshNotifications() async {
|
||||
html.window.location.reload();
|
||||
// var responseNotification = await http.get(Uri.parse(
|
||||
// "$baseAPI/notifications/${widget.signedInUser.app_id}?amount=$amount"));
|
||||
// List<MIHNotification> notifi;
|
||||
// if (responseNotification.statusCode == 200) {
|
||||
// String body = responseNotification.body;
|
||||
// // var decodedData = jsonDecode(body);
|
||||
// // MIHNotification notifications = MIHNotification.fromJson(decodedData);
|
||||
|
||||
// Iterable l = jsonDecode(body);
|
||||
// //print("Here2");
|
||||
// List<MIHNotification> notifications = List<MIHNotification>.from(
|
||||
// l.map((model) => MIHNotification.fromJson(model)));
|
||||
// notifi = notifications;
|
||||
// } else {
|
||||
// notifi = [];
|
||||
// }
|
||||
// setState(() {
|
||||
// notifiList = notifi;
|
||||
// });
|
||||
// notificationPopUp();
|
||||
}
|
||||
|
||||
void notificationPopUp() {
|
||||
if (hasNewNotifications()) {
|
||||
showDialog(
|
||||
barrierColor: const Color(0x01000000),
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return MIHNotificationMessage(
|
||||
arguments: NotificationArguments(
|
||||
"Unread Notifications",
|
||||
"You have unread notifications waiting for you.",
|
||||
() {
|
||||
Navigator.of(context).pop();
|
||||
//Scaffold.of(context).openEndDrawer();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
searchController.dispose();
|
||||
proPicController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
setState(() {
|
||||
pbswitch = setApps(persHTList, busHTList);
|
||||
businessUserSwitch = false;
|
||||
notifiList = widget.notifications;
|
||||
});
|
||||
if (!widget.personalSelected) {
|
||||
setState(() {
|
||||
_selectedIndex = 1;
|
||||
});
|
||||
}
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
notificationPopUp();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Size size = MediaQuery.sizeOf(context);
|
||||
final double width = size.width;
|
||||
final double height = size.height;
|
||||
|
||||
return SwipeDetector(
|
||||
onSwipeLeft: (offset) {
|
||||
if (_selectedIndex == 0) {
|
||||
setState(() {
|
||||
_selectedIndex = 1;
|
||||
});
|
||||
}
|
||||
//print("swipe left");
|
||||
},
|
||||
onSwipeRight: (offset) {
|
||||
if (_selectedIndex == 1) {
|
||||
setState(() {
|
||||
_selectedIndex = 0;
|
||||
});
|
||||
}
|
||||
//print("swipe right");
|
||||
},
|
||||
child: MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: getSecondaryActionButton(),
|
||||
body: getBody(width, height),
|
||||
actionDrawer: getActionDrawer(),
|
||||
secondaryActionDrawer: getSecondaryActionDrawer(),
|
||||
bottomNavBar: getBottomNavBar(),
|
||||
pullDownToRefresh: true,
|
||||
onPullDown: refreshNotifications,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
155
Frontend/lib/mih_packages/mih_home/mih_profile_getter.dart
Normal file
155
Frontend/lib/mih_packages/mih_home/mih_profile_getter.dart
Normal file
@@ -0,0 +1,155 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../mih_apis/mih_api_calls.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
import '../../mih_objects/business_user.dart';
|
||||
import 'mih_home.dart';
|
||||
|
||||
class MIHProfileGetter extends StatefulWidget {
|
||||
final bool personalSelected;
|
||||
const MIHProfileGetter({
|
||||
super.key,
|
||||
required this.personalSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MIHProfileGetter> createState() => _MIHProfileGetterState();
|
||||
}
|
||||
|
||||
class _MIHProfileGetterState extends State<MIHProfileGetter> {
|
||||
String useremail = "";
|
||||
int amount = 10;
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
late Future<HomeArguments> profile;
|
||||
|
||||
String proPicUrl = "empty";
|
||||
ImageProvider<Object>? propicFile;
|
||||
|
||||
ImageProvider<Object>? isPictureAvailable(String url) {
|
||||
if (url == "") {
|
||||
return const AssetImage('images/i-dont-know-2.png');
|
||||
} else if (url != "") {
|
||||
return NetworkImage(url);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
bool isUserNew(AppUser signedInUser) {
|
||||
if (signedInUser.fname == "") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isDevActive() {
|
||||
if (AppEnviroment.getEnv() == "Dev") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isBusinessUser(AppUser signedInUser) {
|
||||
if (signedInUser.type == "personal") {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool isBusinessUserNew(BusinessUser? businessUser) {
|
||||
if (businessUser == null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// <a href="https://www.flaticon.com/free-icons/dont-know" title="dont know icons">Dont know icons created by Freepik - Flaticon</a>
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
//profile = getProfile();
|
||||
profile = MIHApiCalls().getProfile(amount);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: profile,
|
||||
builder: (BuildContext context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.hasData) {
|
||||
return MIHHome(
|
||||
signedInUser: snapshot.requireData.signedInUser,
|
||||
businessUser: snapshot.data!.businessUser,
|
||||
business: snapshot.data!.business,
|
||||
notifications: snapshot.data!.notifi,
|
||||
propicFile: isPictureAvailable(snapshot.data!.profilePicUrl),
|
||||
isUserNew: isUserNew(snapshot.requireData.signedInUser),
|
||||
isBusinessUser: isBusinessUser(snapshot.requireData.signedInUser),
|
||||
isBusinessUserNew: isBusinessUserNew(snapshot.data!.businessUser),
|
||||
isDevActive: isDevActive(),
|
||||
personalSelected: widget.personalSelected,
|
||||
);
|
||||
} else {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: MIHAction(
|
||||
icon: const Icon(Icons.refresh),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).popAndPushNamed("/");
|
||||
},
|
||||
),
|
||||
header: const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"Mzanzi Innovation Hub",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
secondaryActionButton: null,
|
||||
body: MIHBody(
|
||||
borderOn: false,
|
||||
bodyItems: [
|
||||
Center(
|
||||
child: Text(
|
||||
'${snapshot.error} occurred',
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
}
|
||||
}
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
import 'package:http/http.dart' as http2;
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_file_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_components/mih_profile_picture.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
|
||||
class ProfileUserUpdate extends StatefulWidget {
|
||||
final AppProfileUpdateArguments arguments;
|
||||
// final AppUser signedInUser;
|
||||
// final ImageProvider<Object>? propicFile;
|
||||
const ProfileUserUpdate({
|
||||
super.key,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ProfileUserUpdate> createState() => _ProfileUserUpdateState();
|
||||
}
|
||||
|
||||
class _ProfileUserUpdateState extends State<ProfileUserUpdate> {
|
||||
final proPicController = TextEditingController();
|
||||
final usernameController = TextEditingController();
|
||||
final fnameController = TextEditingController();
|
||||
final lnameController = TextEditingController();
|
||||
|
||||
PlatformFile? proPic;
|
||||
late ImageProvider<Object>? propicPreview;
|
||||
late bool businessUser;
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
late String oldProPicName;
|
||||
|
||||
Future<void> deleteFileApiCall(String filename) async {
|
||||
// delete file from minio
|
||||
var fname = filename.replaceAll(RegExp(r' '), '-');
|
||||
var filePath =
|
||||
"${widget.arguments.signedInUser.app_id}/profile_files/$fname";
|
||||
var response = await http.delete(
|
||||
Uri.parse("${AppEnviroment.baseApiUrl}/minio/delete/file/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{"file_path": filePath}),
|
||||
);
|
||||
//print("Here4");
|
||||
//print(response.statusCode);
|
||||
if (response.statusCode == 200) {
|
||||
//SQL delete
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getFileUrlApiCall(String filePath) async {
|
||||
if (widget.arguments.signedInUser.pro_pic_path == "") {
|
||||
return "";
|
||||
} else if (AppEnviroment.getEnv() == "Dev") {
|
||||
return "${AppEnviroment.baseFileUrl}/mih/$filePath";
|
||||
} else {
|
||||
var url = "${AppEnviroment.baseApiUrl}/minio/pull/file/$filePath/prod";
|
||||
var response = await http.get(Uri.parse(url));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
String body = response.body;
|
||||
var decodedData = jsonDecode(body);
|
||||
|
||||
return decodedData['minioURL'];
|
||||
} else {
|
||||
throw Exception(
|
||||
"Error: GetUserData status code ${response.statusCode}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> uploadSelectedFile(PlatformFile? file) async {
|
||||
//print("MIH Profile Picture: $file");
|
||||
//var strem = new http.ByteStream.fromBytes(file.bytes.)
|
||||
//start loading circle
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
var token = await SuperTokens.getAccessToken();
|
||||
var request = http2.MultipartRequest(
|
||||
'POST', Uri.parse("${AppEnviroment.baseApiUrl}/minio/upload/file/"));
|
||||
request.headers['accept'] = 'application/json';
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['Content-Type'] = 'multipart/form-data';
|
||||
request.fields['app_id'] = widget.arguments.signedInUser.app_id;
|
||||
request.fields['folder'] = "profile_files";
|
||||
request.files.add(await http2.MultipartFile.fromBytes('file', file!.bytes!,
|
||||
filename: file.name.replaceAll(RegExp(r' '), '-')));
|
||||
var response1 = await request.send();
|
||||
if (response1.statusCode == 200) {
|
||||
deleteFileApiCall(oldProPicName);
|
||||
|
||||
// end loading circle
|
||||
//Navigator.of(context).pop();
|
||||
// String message =
|
||||
// "The file ${file.name.replaceAll(RegExp(r' '), '-')} has been successfully generated and added to ${widget.signedInUser.fname} ${widget.signedInUser.lname}'s record. You can now access and download it for their use.";
|
||||
// successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
bool isFieldsFilled() {
|
||||
if (fnameController.text.isEmpty ||
|
||||
lnameController.text.isEmpty ||
|
||||
usernameController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateUserApiCall() async {
|
||||
var fname = proPicController.text.replaceAll(RegExp(r' '), '-');
|
||||
var filePath =
|
||||
"${widget.arguments.signedInUser.app_id}/profile_files/$fname";
|
||||
var profileType;
|
||||
if (businessUser) {
|
||||
profileType = "business";
|
||||
} else {
|
||||
profileType = "personal";
|
||||
}
|
||||
if (isUsernameValid(usernameController.text) == false) {
|
||||
usernamePopUp();
|
||||
} else {
|
||||
var response = await http.put(
|
||||
Uri.parse("${AppEnviroment.baseApiUrl}/user/update/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"idusers": widget.arguments.signedInUser.idUser,
|
||||
"username": usernameController.text,
|
||||
"fnam": fnameController.text,
|
||||
"lname": lnameController.text,
|
||||
"type": profileType,
|
||||
"pro_pic_path": filePath,
|
||||
}),
|
||||
);
|
||||
//print("Here4");
|
||||
//print(response.statusCode);
|
||||
if (response.statusCode == 200) {
|
||||
Navigator.of(context)
|
||||
.popAndPushNamed('/', arguments: widget.arguments.signedInUser);
|
||||
String message =
|
||||
"${widget.arguments.signedInUser.email}'s information has been updated successfully!";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isBusinessUser() {
|
||||
if (widget.arguments.signedInUser.type == "personal") {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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 usernamePopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Invalid Username");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool isUsernameValid(String username) {
|
||||
return RegExp(r'^(?=[a-zA-Z0-9._]{8,20}$)(?!.*[_.]{2})[^_.].*[^_.]$')
|
||||
.hasMatch(username);
|
||||
}
|
||||
|
||||
Future<void> submitForm() async {
|
||||
if (isFieldsFilled()) {
|
||||
if (oldProPicName != proPicController.text) {
|
||||
await uploadSelectedFile(proPic);
|
||||
}
|
||||
await updateUserApiCall();
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
Navigator.of(context).popAndPushNamed(
|
||||
'/',
|
||||
arguments: true,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"Mzansi Profile",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: false,
|
||||
bodyItems: [
|
||||
//displayProPic(),
|
||||
MIHProfilePicture(
|
||||
profilePictureFile: widget.arguments.propicFile,
|
||||
proPicController: proPicController,
|
||||
proPic: proPic,
|
||||
width: 155,
|
||||
radius: 70,
|
||||
drawerMode: false,
|
||||
editable: true,
|
||||
onChange: (newProPic) {
|
||||
setState(() {
|
||||
proPic = newProPic;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25.0),
|
||||
Visibility(
|
||||
visible: false,
|
||||
child: MIHFileField(
|
||||
controller: proPicController,
|
||||
hintText: "Profile Picture",
|
||||
editable: false,
|
||||
required: false,
|
||||
onPressed: () async {
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png'],
|
||||
);
|
||||
if (result == null) return;
|
||||
final selectedFile = result.files.first;
|
||||
setState(() {
|
||||
proPic = selectedFile;
|
||||
propicPreview = MemoryImage(proPic!.bytes!);
|
||||
});
|
||||
|
||||
setState(() {
|
||||
proPicController.text = selectedFile.name;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: usernameController,
|
||||
hintText: "Username",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: fnameController,
|
||||
hintText: "First Name",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: lnameController,
|
||||
hintText: "Last Name",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
"Activate Business Account",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Switch(
|
||||
value: businessUser,
|
||||
onChanged: (bool value) {
|
||||
setState(() {
|
||||
businessUser = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 30.0),
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
buttonText: "Update",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
onTap: () {
|
||||
submitForm();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
proPicController.dispose();
|
||||
usernameController.dispose();
|
||||
fnameController.dispose();
|
||||
lnameController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
var proPicName = "";
|
||||
if (widget.arguments.signedInUser.pro_pic_path.isNotEmpty) {
|
||||
proPicName = widget.arguments.signedInUser.pro_pic_path.split("/").last;
|
||||
}
|
||||
setState(() {
|
||||
propicPreview = widget.arguments.propicFile;
|
||||
oldProPicName = proPicName;
|
||||
proPicController.text = proPicName;
|
||||
fnameController.text = widget.arguments.signedInUser.fname;
|
||||
lnameController.text = widget.arguments.signedInUser.lname;
|
||||
usernameController.text = widget.arguments.signedInUser.username;
|
||||
businessUser = isBusinessUser();
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
import '../../mih_objects/patients.dart';
|
||||
import 'patient_add.dart';
|
||||
import 'patient_view.dart';
|
||||
|
||||
class AddOrViewPatient extends StatefulWidget {
|
||||
//final AppUser signedInUser;
|
||||
final PatientViewArguments arguments;
|
||||
const AddOrViewPatient({
|
||||
super.key,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AddOrViewPatient> createState() => _AddOrViewPatientState();
|
||||
}
|
||||
|
||||
class _AddOrViewPatientState extends State<AddOrViewPatient> {
|
||||
late double width;
|
||||
late double height;
|
||||
late Widget loading;
|
||||
|
||||
Future<Patient?> fetchPatient() async {
|
||||
//print("Patien manager page: $endpoint");
|
||||
final response = await http.get(Uri.parse(
|
||||
"${AppEnviroment.baseApiUrl}/patients/${widget.arguments.signedInUser.app_id}"));
|
||||
// print("Here");
|
||||
// print("Body: ${response.body}");
|
||||
// print("Code: ${response.statusCode}");
|
||||
// var errorCode = response.statusCode.toString();
|
||||
// var errorBody = response.body;
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// print("Here1");
|
||||
var decodedData = jsonDecode(response.body);
|
||||
// print("Here2");
|
||||
Patient patients = Patient.fromJson(decodedData as Map<String, dynamic>);
|
||||
// print("Here3");
|
||||
// print(patients);
|
||||
return patients;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var size = MediaQuery.of(context).size;
|
||||
setState(() {
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
});
|
||||
return FutureBuilder(
|
||||
future: fetchPatient(),
|
||||
builder: (ctx, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
// Extracting data from snapshot object
|
||||
//final data = snapshot.data as String;
|
||||
return PatientView(
|
||||
arguments: PatientViewArguments(
|
||||
widget.arguments.signedInUser,
|
||||
snapshot.requireData,
|
||||
null,
|
||||
null,
|
||||
widget.arguments.type,
|
||||
));
|
||||
} else if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
loading = Container(
|
||||
width: width,
|
||||
height: height,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
child: const Mihloadingcircle(),
|
||||
);
|
||||
|
||||
return loading;
|
||||
} else {
|
||||
return AddPatient(signedInUser: widget.arguments.signedInUser);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncfusion_flutter_core/theme.dart';
|
||||
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
|
||||
import "package:universal_html/html.dart" as html;
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_objects/arguments.dart';
|
||||
|
||||
class BuildFileView extends StatefulWidget {
|
||||
final String link;
|
||||
final String path;
|
||||
const BuildFileView({
|
||||
super.key,
|
||||
required this.link,
|
||||
required this.path,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildFileView> createState() => _BuildFileViewState();
|
||||
}
|
||||
|
||||
class _BuildFileViewState extends State<BuildFileView> {
|
||||
late PdfViewerController pdfViewerController = PdfViewerController();
|
||||
//late TextEditingController currentPageController = TextEditingController();
|
||||
double startZoomLevel = 1;
|
||||
|
||||
String getExtType(String path) {
|
||||
//print(pdfLink.split(".")[1]);
|
||||
return path.split(".").last;
|
||||
}
|
||||
|
||||
String getFileName(String path) {
|
||||
//print(pdfLink.split(".")[1]);
|
||||
return path.split("/").last;
|
||||
}
|
||||
|
||||
void printDocument() async {
|
||||
print("Printing ${widget.path.split("/").last}");
|
||||
http.Response response = await http.get(Uri.parse(widget.link));
|
||||
var pdfData = response.bodyBytes;
|
||||
Navigator.of(context).pushNamed(
|
||||
'/file-veiwer/print-preview',
|
||||
arguments: PrintPreviewArguments(
|
||||
pdfData,
|
||||
getFileName(
|
||||
widget.path,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
pdfViewerController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// double width = MediaQuery.sizeOf(context).width;
|
||||
//double height = MediaQuery.sizeOf(context).height;
|
||||
if (getExtType(widget.path).toLowerCase() == "pdf") {
|
||||
//print(widget.pdfLink);
|
||||
return Expanded(
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
SfPdfViewerTheme(
|
||||
data: SfPdfViewerThemeData(
|
||||
backgroundColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
child: SfPdfViewer.network(
|
||||
widget.link,
|
||||
controller: pdfViewerController,
|
||||
interactionMode: PdfInteractionMode.pan,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
right: 10,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton.filled(
|
||||
iconSize: 35,
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
printDocument();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.print,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
left: 10,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton.filled(
|
||||
iconSize: 35,
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
html.window.open(
|
||||
widget.link,
|
||||
// '${AppEnviroment.baseFileUrl}/mih/$filePath',
|
||||
'download');
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.download,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Expanded(
|
||||
// height: height,
|
||||
// padding: const EdgeInsets.all(10.0),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
InteractiveViewer(
|
||||
//constrained: true,
|
||||
//clipBehavior: Clip.antiAlias,
|
||||
maxScale: 5.0,
|
||||
//minScale: 0.,
|
||||
child: Image.network(widget.link),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
right: 10,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton.filled(
|
||||
iconSize: 35,
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
//expandImage(width, height);
|
||||
Navigator.of(context).pushNamed(
|
||||
'/file-veiwer',
|
||||
arguments: FileViewArguments(
|
||||
widget.link,
|
||||
widget.path,
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.fullscreen,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
left: 10,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton.filled(
|
||||
iconSize: 35,
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
html.window.open(
|
||||
widget.link,
|
||||
// '${AppEnviroment.baseFileUrl}/mih/$filePath',
|
||||
'download');
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.download,
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,398 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_components/mih_layout/mih_window.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_delete_message.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../../mih_env/env.dart';
|
||||
import '../../../mih_objects/app_user.dart';
|
||||
import '../../../mih_objects/arguments.dart';
|
||||
import '../../../mih_objects/business.dart';
|
||||
import '../../../mih_objects/business_user.dart';
|
||||
import '../../../mih_objects/files.dart';
|
||||
import '../../../mih_objects/patients.dart';
|
||||
import 'build_file_view.dart';
|
||||
|
||||
class BuildFilesList extends StatefulWidget {
|
||||
final AppUser signedInUser;
|
||||
final List<PFile> files;
|
||||
final Patient selectedPatient;
|
||||
final Business? business;
|
||||
final BusinessUser? businessUser;
|
||||
final String type;
|
||||
const BuildFilesList({
|
||||
super.key,
|
||||
required this.files,
|
||||
required this.signedInUser,
|
||||
required this.selectedPatient,
|
||||
required this.business,
|
||||
required this.businessUser,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildFilesList> createState() => _BuildFilesListState();
|
||||
}
|
||||
|
||||
class _BuildFilesListState extends State<BuildFilesList> {
|
||||
int indexOn = 0;
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
final basefile = AppEnviroment.baseFileUrl;
|
||||
String fileUrl = "";
|
||||
|
||||
Future<String> getFileUrlApiCall(String filePath) async {
|
||||
var url = "$baseAPI/minio/pull/file/${AppEnviroment.getEnv()}/$filePath";
|
||||
//print(url);
|
||||
var response = await http.get(Uri.parse(url));
|
||||
// print("here1");
|
||||
//print(response.statusCode);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
//print("here2");
|
||||
String body = response.body;
|
||||
//print(body);
|
||||
//print("here3");
|
||||
var decodedData = jsonDecode(body);
|
||||
//print("Dedoced: ${decodedData['minioURL']}");
|
||||
|
||||
return decodedData['minioURL'];
|
||||
//AppUser u = AppUser.fromJson(decodedData);
|
||||
// print(u.email);
|
||||
//return "AlometThere";
|
||||
} else {
|
||||
throw Exception("Error: GetUserData status code ${response.statusCode}");
|
||||
}
|
||||
|
||||
//print(url);
|
||||
// var response = await http.get(Uri.parse(url));
|
||||
// // print("here1");
|
||||
// //print(response.statusCode);
|
||||
|
||||
// if (response.statusCode == 200) {
|
||||
// //print("here2");
|
||||
// String body = response.body;
|
||||
// //print(body);
|
||||
// //print("here3");
|
||||
// var decodedData = jsonDecode(body);
|
||||
// //print("Dedoced: ${decodedData['minioURL']}");
|
||||
|
||||
// return decodedData['minioURL'];
|
||||
// //AppUser u = AppUser.fromJson(decodedData);
|
||||
// // print(u.email);
|
||||
// //return "AlometThere";
|
||||
// } else {
|
||||
// throw Exception("Error: GetUserData status code ${response.statusCode}");
|
||||
// }
|
||||
}
|
||||
|
||||
Future<void> deleteFileApiCall(String filePath, int fileID) async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
// delete file from minio
|
||||
var response = await http.delete(
|
||||
Uri.parse("$baseAPI/minio/delete/file/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{"file_path": filePath}),
|
||||
);
|
||||
//print("Here4");
|
||||
//print(response.statusCode);
|
||||
if (response.statusCode == 200) {
|
||||
//SQL delete
|
||||
var response2 = await http.delete(
|
||||
Uri.parse("$baseAPI/files/delete/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{"idpatient_files": fileID}),
|
||||
);
|
||||
if (response2.statusCode == 200) {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
//print(widget.business);
|
||||
if (widget.business == null) {
|
||||
Navigator.of(context).pushNamed('/patient-manager/patient',
|
||||
arguments: PatientViewArguments(
|
||||
widget.signedInUser,
|
||||
widget.selectedPatient,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
"personal"));
|
||||
} else {
|
||||
Navigator.of(context).pushNamed('/patient-manager/patient',
|
||||
arguments: PatientViewArguments(
|
||||
widget.signedInUser,
|
||||
widget.selectedPatient,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
"business"));
|
||||
}
|
||||
|
||||
// Navigator.of(context)
|
||||
// .pushNamed('/patient-profile', arguments: widget.signedInUser);
|
||||
// setState(() {});
|
||||
String message =
|
||||
"The File has been deleted successfully. This means it will no longer be visible on your and cannot be used for future appointments.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
} 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 deleteFilePopUp(String filePath, int fileID) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHDeleteMessage(
|
||||
deleteType: "File",
|
||||
onTap: () async {
|
||||
await deleteFileApiCall(filePath, fileID);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void viewFilePopUp(String fileName, String filePath, int fileID, String url) {
|
||||
bool hasAccessToDelete = false;
|
||||
if (widget.type == "business") {
|
||||
hasAccessToDelete = true;
|
||||
}
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: true,
|
||||
windowTitle: fileName,
|
||||
windowBody: [
|
||||
BuildFileView(
|
||||
link: url,
|
||||
path: filePath,
|
||||
//pdfLink: '${AppEnviroment.baseFileUrl}/mih/$filePath',
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
)
|
||||
],
|
||||
windowTools: [
|
||||
Visibility(
|
||||
visible: hasAccessToDelete,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
deleteFilePopUp(filePath, fileID);
|
||||
},
|
||||
icon: Icon(
|
||||
size: 35,
|
||||
Icons.delete,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
);
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => Dialog(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// Container(
|
||||
// padding: const EdgeInsets.all(10.0),
|
||||
// width: 800.0,
|
||||
// //height: 475.0,
|
||||
// decoration: BoxDecoration(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
// borderRadius: BorderRadius.circular(25.0),
|
||||
// border: Border.all(
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// width: 5.0),
|
||||
// ),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// const SizedBox(
|
||||
// height: 25,
|
||||
// ),
|
||||
// Text(
|
||||
// fileName,
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// fontSize: 35.0,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 25.0),
|
||||
// Expanded(
|
||||
// child: BuildFileView(
|
||||
// link: url,
|
||||
// path: filePath,
|
||||
// //pdfLink: '${AppEnviroment.baseFileUrl}/mih/$filePath',
|
||||
// )),
|
||||
// const SizedBox(height: 30.0),
|
||||
// SizedBox(
|
||||
// width: 300,
|
||||
// height: 50,
|
||||
// child: MIHButton(
|
||||
// onTap: () {
|
||||
// html.window.open(
|
||||
// url,
|
||||
// // '${AppEnviroment.baseFileUrl}/mih/$filePath',
|
||||
// 'download');
|
||||
// },
|
||||
// buttonText: "Dowload",
|
||||
// buttonColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// textColor:
|
||||
// MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 5,
|
||||
// right: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pop(context);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.close,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 5,
|
||||
// left: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// deleteFilePopUp(filePath, fileID);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.delete,
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (widget.files.isNotEmpty) {
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
);
|
||||
},
|
||||
itemCount: widget.files.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text(
|
||||
widget.files[index].file_name,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
widget.files[index].insert_date,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
// trailing: Icon(
|
||||
// Icons.arrow_forward,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
onTap: () async {
|
||||
await getFileUrlApiCall(widget.files[index].file_path)
|
||||
.then((urlHere) {
|
||||
//print(url);
|
||||
setState(() {
|
||||
fileUrl = urlHere;
|
||||
});
|
||||
});
|
||||
|
||||
viewFilePopUp(
|
||||
widget.files[index].file_name,
|
||||
widget.files[index].file_path,
|
||||
widget.files[index].idpatient_files,
|
||||
fileUrl);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return const Center(
|
||||
child: Text(
|
||||
"No Documents Available",
|
||||
style: TextStyle(fontSize: 25, color: Colors.grey),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_objects/medicine.dart';
|
||||
|
||||
class BuildMedicinesList extends StatefulWidget {
|
||||
final TextEditingController contoller;
|
||||
final List<Medicine> medicines;
|
||||
//final searchString;
|
||||
|
||||
const BuildMedicinesList({
|
||||
super.key,
|
||||
required this.contoller,
|
||||
required this.medicines,
|
||||
//required this.searchString,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildMedicinesList> createState() => _BuildMedicinesListState();
|
||||
}
|
||||
|
||||
class _BuildMedicinesListState extends State<BuildMedicinesList> {
|
||||
int indexOn = 0;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.separated(
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
);
|
||||
},
|
||||
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,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
"${widget.medicines[index].unit} - ${widget.medicines[index].form}",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
widget.contoller.text =
|
||||
"${widget.medicines[index].name}%t${widget.medicines[index].unit}%t${widget.medicines[index].form}";
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
},
|
||||
trailing: Icon(
|
||||
Icons.arrow_forward,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_multiline_text_input.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../../mih_components/mih_layout/mih_window.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_delete_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_env/env.dart';
|
||||
import '../../../mih_objects/app_user.dart';
|
||||
import '../../../mih_objects/arguments.dart';
|
||||
import '../../../mih_objects/business.dart';
|
||||
import '../../../mih_objects/business_user.dart';
|
||||
import '../../../mih_objects/notes.dart';
|
||||
import '../../../mih_objects/patients.dart';
|
||||
|
||||
class BuildNotesList extends StatefulWidget {
|
||||
final AppUser signedInUser;
|
||||
final List<Note> notes;
|
||||
final Patient selectedPatient;
|
||||
final Business? business;
|
||||
final BusinessUser? businessUser;
|
||||
final String type;
|
||||
const BuildNotesList({
|
||||
super.key,
|
||||
required this.notes,
|
||||
required this.signedInUser,
|
||||
required this.selectedPatient,
|
||||
required this.business,
|
||||
required this.businessUser,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildNotesList> createState() => _BuildNotesListState();
|
||||
}
|
||||
|
||||
class _BuildNotesListState extends State<BuildNotesList> {
|
||||
final noteTitleController = TextEditingController();
|
||||
final noteTextController = TextEditingController();
|
||||
final businessNameController = TextEditingController();
|
||||
final userNameController = TextEditingController();
|
||||
final dateController = TextEditingController();
|
||||
int indexOn = 0;
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
Future<void> deleteNoteApiCall(int NoteId) async {
|
||||
var response = await http.delete(
|
||||
Uri.parse("$baseAPI/notes/delete/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{"idpatient_notes": NoteId}),
|
||||
);
|
||||
//print("Here4");
|
||||
//print(response.statusCode);
|
||||
if (response.statusCode == 200) {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
if (widget.business == null) {
|
||||
Navigator.of(context).pushNamed('/patient-manager/patient',
|
||||
arguments: PatientViewArguments(
|
||||
widget.signedInUser,
|
||||
widget.selectedPatient,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
"personal"));
|
||||
} else {
|
||||
Navigator.of(context).pushNamed('/patient-manager/patient',
|
||||
arguments: PatientViewArguments(
|
||||
widget.signedInUser,
|
||||
widget.selectedPatient,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
"business"));
|
||||
}
|
||||
setState(() {});
|
||||
String message =
|
||||
"The note has been deleted successfully. This means it will no longer be visible on your and cannot be used for future appointments.";
|
||||
successPopUp(message);
|
||||
} 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 deletePatientPopUp(int NoteId) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHDeleteMessage(
|
||||
deleteType: "Note",
|
||||
onTap: () {
|
||||
deleteNoteApiCall(NoteId);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void viewNotePopUp(Note selectednote) {
|
||||
setState(() {
|
||||
noteTitleController.text = selectednote.note_name;
|
||||
noteTextController.text = selectednote.note_text;
|
||||
businessNameController.text = selectednote.doc_office;
|
||||
userNameController.text = selectednote.doctor;
|
||||
dateController.text = selectednote.insert_date;
|
||||
});
|
||||
bool hasAccessToDelete = false;
|
||||
if (widget.type == "business" &&
|
||||
selectednote.doc_office == widget.business!.Name) {
|
||||
hasAccessToDelete = true;
|
||||
}
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: true,
|
||||
windowTitle: selectednote.note_name,
|
||||
windowTools: [
|
||||
Visibility(
|
||||
visible: hasAccessToDelete,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
deletePatientPopUp(selectednote.idpatient_notes);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.delete,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
windowBody: [
|
||||
MIHTextField(
|
||||
controller: businessNameController,
|
||||
hintText: "Office",
|
||||
editable: false,
|
||||
required: false,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: userNameController,
|
||||
hintText: "Created By",
|
||||
editable: false,
|
||||
required: false,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: dateController,
|
||||
hintText: "Created Date",
|
||||
editable: false,
|
||||
required: false,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: noteTitleController,
|
||||
hintText: "Note Title",
|
||||
editable: false,
|
||||
required: false,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
Expanded(
|
||||
child: MIHMLTextField(
|
||||
controller: noteTextController,
|
||||
hintText: "Note Details",
|
||||
editable: false,
|
||||
required: false,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => Dialog(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// Container(
|
||||
// padding: const EdgeInsets.all(15.0),
|
||||
// width: 700.0,
|
||||
// //height: 475.0,
|
||||
// decoration: BoxDecoration(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
// borderRadius: BorderRadius.circular(25.0),
|
||||
// border: Border.all(
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// width: 5.0),
|
||||
// ),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.max,
|
||||
// children: [
|
||||
// const SizedBox(
|
||||
// height: 25,
|
||||
// ),
|
||||
// Text(
|
||||
// selectednote.note_name,
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// fontSize: 35.0,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 25.0),
|
||||
// SizedBox(
|
||||
// width: 700,
|
||||
// child: MIHTextField(
|
||||
// controller: businessNameController,
|
||||
// hintText: "Office",
|
||||
// editable: false,
|
||||
// required: false,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// SizedBox(
|
||||
// width: 700,
|
||||
// child: MIHTextField(
|
||||
// controller: userNameController,
|
||||
// hintText: "Created By",
|
||||
// editable: false,
|
||||
// required: false,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// SizedBox(
|
||||
// width: 700,
|
||||
// child: MIHTextField(
|
||||
// controller: dateController,
|
||||
// hintText: "Created Date",
|
||||
// editable: false,
|
||||
// required: false,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// SizedBox(
|
||||
// width: 700,
|
||||
// child: MIHTextField(
|
||||
// controller: noteTitleController,
|
||||
// hintText: "Note Title",
|
||||
// editable: false,
|
||||
// required: false,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// Expanded(
|
||||
// child: MIHMLTextField(
|
||||
// controller: noteTextController,
|
||||
// hintText: "Note Details",
|
||||
// editable: false,
|
||||
// required: false,
|
||||
// ),
|
||||
// ),
|
||||
// //const SizedBox(height: 25.0),
|
||||
// // SizedBox(
|
||||
// // width: 300,
|
||||
// // height: 100,
|
||||
// // child: MIHButton(
|
||||
// // onTap: () {
|
||||
// // Navigator.pop(context);
|
||||
// // },
|
||||
// // buttonText: "Close",
|
||||
// // buttonColor: Colors.blueAccent,
|
||||
// // textColor: Colors.white,
|
||||
// // ),
|
||||
// // )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 5,
|
||||
// right: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pop(context);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.close,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 5,
|
||||
// left: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// deletePatientPopUp(selectednote.idpatient_notes);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.delete,
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
noteTextController.dispose();
|
||||
businessNameController.dispose();
|
||||
userNameController.dispose();
|
||||
dateController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (widget.notes.isNotEmpty) {
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
);
|
||||
},
|
||||
itemCount: widget.notes.length,
|
||||
itemBuilder: (context, index) {
|
||||
String notePreview = widget.notes[index].note_text;
|
||||
if (notePreview.length > 30) {
|
||||
notePreview = "${notePreview.substring(0, 30)} ...";
|
||||
}
|
||||
return ListTile(
|
||||
title: Text(
|
||||
"${widget.notes[index].note_name}\n${widget.notes[index].doc_office} - ${widget.notes[index].doctor}",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
"${widget.notes[index].insert_date}:\n$notePreview",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
), //Text(widget.notes[index].note_text),
|
||||
trailing: Icon(
|
||||
Icons.arrow_forward,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
onTap: () {
|
||||
viewNotePopUp(widget.notes[index]);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return const Center(
|
||||
child: Text(
|
||||
"No Notes Available",
|
||||
style: TextStyle(fontSize: 25, color: Colors.grey),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_apis/mih_api_calls.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_date_input.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_time_input.dart';
|
||||
import '../../../mih_components/mih_layout/mih_window.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_warning_message.dart';
|
||||
import '../../../mih_env/env.dart';
|
||||
import '../../../mih_objects/app_user.dart';
|
||||
import '../../../mih_objects/arguments.dart';
|
||||
import '../../../mih_objects/business.dart';
|
||||
import '../../../mih_objects/patient_access.dart';
|
||||
import '../../../mih_objects/patients.dart';
|
||||
|
||||
class BuildPatientAccessList extends StatefulWidget {
|
||||
final List<PatientAccess> patientAccesses;
|
||||
final AppUser signedInUser;
|
||||
final Business? business;
|
||||
final BusinessArguments arguments;
|
||||
|
||||
const BuildPatientAccessList({
|
||||
super.key,
|
||||
required this.patientAccesses,
|
||||
required this.signedInUser,
|
||||
required this.business,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildPatientAccessList> createState() => _BuildPatientsListState();
|
||||
}
|
||||
|
||||
class _BuildPatientsListState extends State<BuildPatientAccessList> {
|
||||
TextEditingController dateController = TextEditingController();
|
||||
TextEditingController timeController = TextEditingController();
|
||||
TextEditingController idController = TextEditingController();
|
||||
TextEditingController fnameController = TextEditingController();
|
||||
TextEditingController lnameController = TextEditingController();
|
||||
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
Future<void> addPatientAppointmentAPICall(int index) async {
|
||||
var response = await http.post(
|
||||
Uri.parse("$baseAPI/queue/insert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": widget.business!.business_id,
|
||||
"app_id": widget.patientAccesses[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 patientAccesses 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.arguments.signedInUser,
|
||||
widget.arguments.businessUser,
|
||||
widget.arguments.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.patientAccesses[index].app_id,
|
||||
"notification_type": "New Appointment Booked",
|
||||
"notification_message":
|
||||
"A new Appointment has been booked by ${widget.arguments.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) {
|
||||
MIHApiCalls.addAppointmentAPICall(
|
||||
widget.arguments.business!.business_id,
|
||||
widget.patientAccesses[index].app_id,
|
||||
dateController.text,
|
||||
timeController.text,
|
||||
widget.arguments,
|
||||
context,
|
||||
);
|
||||
//addPatientAppointmentAPICall(index);
|
||||
}
|
||||
|
||||
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() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "No Access");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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: () {
|
||||
print("Book an Appointment!!!");
|
||||
appointmentPopUp(index);
|
||||
|
||||
// //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");
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
},
|
||||
),
|
||||
),
|
||||
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.arguments.businessUser,
|
||||
widget.business,
|
||||
"business",
|
||||
));
|
||||
},
|
||||
),
|
||||
),
|
||||
])
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget displayAccessTile(int index) {
|
||||
var firstName = widget.patientAccesses[index].fname;
|
||||
var lastName = widget.patientAccesses[index].lname;
|
||||
String access = widget.patientAccesses[index].status.toUpperCase();
|
||||
TextSpan accessWithColour;
|
||||
var hasAccess = false;
|
||||
hasAccess = hasAccessToProfile(index);
|
||||
//print(hasAccess);
|
||||
if (access == "APPROVED") {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.successColor()));
|
||||
} else if (access == "PENDING") {
|
||||
accessWithColour = TextSpan(
|
||||
text: "$access\n",
|
||||
style: TextStyle(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.messageTextColor()));
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
},
|
||||
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) {
|
||||
//final patient = widget.patientAccesses[index].id_no.contains(widget.searchString);
|
||||
//print(index);
|
||||
return displayAccessTile(index);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,670 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_apis/mih_api_calls.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_date_input.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_time_input.dart';
|
||||
import '../../../mih_components/mih_layout/mih_window.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_warning_message.dart';
|
||||
import '../../../mih_env/env.dart';
|
||||
import '../../../mih_objects/app_user.dart';
|
||||
import '../../../mih_objects/arguments.dart';
|
||||
import '../../../mih_objects/business.dart';
|
||||
import '../../../mih_objects/patients.dart';
|
||||
|
||||
class BuildPatientsList extends StatefulWidget {
|
||||
final List<Patient> patients;
|
||||
final AppUser signedInUser;
|
||||
final Business? business;
|
||||
final BusinessArguments arguments;
|
||||
|
||||
const BuildPatientsList({
|
||||
super.key,
|
||||
required this.patients,
|
||||
required this.signedInUser,
|
||||
required this.business,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildPatientsList> createState() => _BuildPatientsListState();
|
||||
}
|
||||
|
||||
class _BuildPatientsListState extends State<BuildPatientsList> {
|
||||
TextEditingController dateController = TextEditingController();
|
||||
TextEditingController timeController = TextEditingController();
|
||||
TextEditingController idController = TextEditingController();
|
||||
TextEditingController fnameController = TextEditingController();
|
||||
TextEditingController lnameController = TextEditingController();
|
||||
TextEditingController accessStatusController = TextEditingController();
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
Future<void> addPatientAppointmentAPICall(int index) async {
|
||||
var response = await http.post(
|
||||
Uri.parse("$baseAPI/queue/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.arguments.signedInUser,
|
||||
widget.arguments.businessUser,
|
||||
widget.arguments.business,
|
||||
),
|
||||
);
|
||||
successPopUp(message);
|
||||
addAccessReviewNotificationAPICall(index);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
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.arguments.signedInUser,
|
||||
widget.arguments.businessUser,
|
||||
widget.arguments.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.arguments.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) {
|
||||
MIHApiCalls.addAppointmentAPICall(
|
||||
widget.arguments.business!.business_id,
|
||||
widget.patients[index].app_id,
|
||||
dateController.text,
|
||||
timeController.text,
|
||||
widget.arguments,
|
||||
context,
|
||||
);
|
||||
//addPatientAppointmentAPICall(index);
|
||||
}
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
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.",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20.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.arguments.businessUser,
|
||||
widget.business,
|
||||
"business",
|
||||
));
|
||||
} else {
|
||||
noAccessWarning();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: !hasAccess && accessStatus != "pending",
|
||||
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.arguments,
|
||||
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);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,843 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../../mih_apis/mih_api_calls.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_date_input.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../../mih_components/mih_inputs_and_buttons/mih_time_input.dart';
|
||||
import '../../../mih_components/mih_layout/mih_window.dart';
|
||||
import '../../../mih_components/mih_pop_up_messages/mih_delete_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_warning_message.dart';
|
||||
import '../../../mih_env/env.dart';
|
||||
import '../../../mih_objects/app_user.dart';
|
||||
import '../../../mih_objects/arguments.dart';
|
||||
import '../../../mih_objects/business.dart';
|
||||
import '../../../mih_objects/business_user.dart';
|
||||
import '../../../mih_objects/patient_queue.dart';
|
||||
import '../../../mih_objects/patients.dart';
|
||||
|
||||
class BuildPatientQueueList extends StatefulWidget {
|
||||
final List<PatientQueue> patientQueue;
|
||||
final AppUser signedInUser;
|
||||
final Business? business;
|
||||
final BusinessUser? businessUser;
|
||||
|
||||
const BuildPatientQueueList({
|
||||
super.key,
|
||||
required this.patientQueue,
|
||||
required this.signedInUser,
|
||||
required this.business,
|
||||
required this.businessUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BuildPatientQueueList> createState() => _BuildPatientsListState();
|
||||
}
|
||||
|
||||
class _BuildPatientsListState extends State<BuildPatientQueueList> {
|
||||
String baseAPI = AppEnviroment.baseApiUrl;
|
||||
TextEditingController dateController = TextEditingController();
|
||||
TextEditingController timeController = TextEditingController();
|
||||
TextEditingController idController = TextEditingController();
|
||||
TextEditingController fnameController = TextEditingController();
|
||||
TextEditingController lnameController = TextEditingController();
|
||||
TextEditingController daysExtensionController = TextEditingController();
|
||||
int counter = 0;
|
||||
|
||||
Future<void> updateAccessAPICall(int index, String accessType) async {
|
||||
var response = await http.put(
|
||||
Uri.parse("$baseAPI/access-requests/update/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"business_id": widget.business!.business_id,
|
||||
"app_id": widget.patientQueue[index].app_id,
|
||||
"date_time": widget.patientQueue[index].date_time,
|
||||
"access": accessType,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
//Navigator.of(context).pushNamed('/home');
|
||||
addCancelledAppointmentNotificationAPICall(index);
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pushNamed(
|
||||
// '/patient-manager',
|
||||
// arguments: BusinessArguments(
|
||||
// widget.signedInUser,
|
||||
// widget.businessUser,
|
||||
// widget.business,
|
||||
// ),
|
||||
// );
|
||||
// String message =
|
||||
// "The appointment for ${widget.patientQueue[index].first_name} ${widget.patientQueue[index].last_name} at ${widget.patientQueue[index].date_time} has been successfully canceled.";
|
||||
|
||||
// successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
// Future<void> extendAccessAPICall(int index, String revokeDate) async {
|
||||
// var response = await http.put(
|
||||
// Uri.parse("$baseAPI/access-requests/extension/"),
|
||||
// headers: <String, String>{
|
||||
// "Content-Type": "application/json; charset=UTF-8"
|
||||
// },
|
||||
// body: jsonEncode(<String, dynamic>{
|
||||
// "business_id": widget.business!.business_id,
|
||||
// "app_id": widget.patientQueue[index].app_id,
|
||||
// "date_time": widget.patientQueue[index].date_time,
|
||||
// "revoke_date": revokeDate,
|
||||
// }),
|
||||
// );
|
||||
// if (response.statusCode == 200) {
|
||||
// addAccessExtensionNotificationAPICall(index, revokeDate);
|
||||
// //addCancelledAppointmentNotificationAPICall(index);
|
||||
// } else {
|
||||
// internetConnectionPopUp();
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<void> updateApointmentAPICall(int index) async {
|
||||
var response = await http.put(
|
||||
Uri.parse("$baseAPI/queue/appoointment/update/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"idpatient_queue": widget.patientQueue[index].idpatient_queue,
|
||||
"date": dateController.text,
|
||||
"time": timeController.text,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
//Navigator.of(context).pushNamed('/home');
|
||||
addRescheduledAppointmentNotificationAPICall(index);
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pushNamed(
|
||||
// '/patient-manager',
|
||||
// arguments: BusinessArguments(
|
||||
// widget.signedInUser,
|
||||
// widget.businessUser,
|
||||
// widget.business,
|
||||
// ),
|
||||
// );
|
||||
|
||||
// String message =
|
||||
// "The appointment has been rescheduled for ${dateController.text} ${timeController.text}.\n\nJust a heads up: We've reset your access to the patient's profile and it will have to be approved again.";
|
||||
|
||||
// successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Patient> fetchPatients(String app_id) async {
|
||||
//print("pat man drawer: " + endpointUserData + widget.userEmail);
|
||||
|
||||
var response = await http.get(Uri.parse("$baseAPI/patients/$app_id"));
|
||||
|
||||
// print(response.statusCode);
|
||||
// print(response.body);
|
||||
if (response.statusCode == 200) {
|
||||
// print("here");
|
||||
String body = response.body;
|
||||
var decodedData = jsonDecode(body);
|
||||
Patient u = Patient.fromJson(decodedData);
|
||||
// print(u.email);
|
||||
//setState(() {
|
||||
//_widgetOptions = setLayout(u);
|
||||
//});
|
||||
return u;
|
||||
} else {
|
||||
throw Exception("Error: GetUserData status code ${response.statusCode}");
|
||||
}
|
||||
}
|
||||
|
||||
void internetConnectionPopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Internet Connection");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void deleteFilePopUp(int index) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHDeleteMessage(
|
||||
deleteType: "appointment",
|
||||
onTap: () async {
|
||||
await updateAccessAPICall(index, "cancelled");
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void successPopUp(String message) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return MIHSuccessMessage(
|
||||
successType: "Success",
|
||||
successMessage: message,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void viewConfirmationPopUp(int index) {
|
||||
String subtitle =
|
||||
"Appointment: ${widget.patientQueue[index].date_time.substring(0, 16).replaceAll("T", " ")}\n";
|
||||
subtitle += "ID No.: ${widget.patientQueue[index].id_no}\n";
|
||||
subtitle +=
|
||||
"Patient: ${widget.patientQueue[index].first_name} ${widget.patientQueue[index].last_name}\n";
|
||||
// subtitle +=
|
||||
// "Patient: ${widget.patientQueue[index].first_name} ${widget.patientQueue[index].last_name}\n\n";
|
||||
//subtitle += "Business Type: ${widget.patientQueue[index].last_name}\n\n";
|
||||
subtitle +=
|
||||
"Would you like to view the patient's profile before the appointment or cancel the appointment now?\n";
|
||||
//"You are about to approve an access request to your patient profile.\nPlease be aware that once approved, ${widget.accessRequests[index].Name} will have access to your profile information until ${widget.accessRequests[index].revoke_date.substring(0, 16).replaceAll("T", " ")}.\nIf you are unsure about an upcoming appointment with ${widget.accessRequests[index].Name}, please contact ${widget.accessRequests[index].contact_no} for clarification before approving this request.\n";
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Appointment Confirmation",
|
||||
windowBody: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Text(
|
||||
subtitle,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
fontSize: 15,
|
||||
//fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
Wrap(
|
||||
runSpacing: 10,
|
||||
spacing: 10,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
//updateAccessAPICall(index, "cancelled");
|
||||
var appointmentDateTime = widget
|
||||
.patientQueue[index].date_time
|
||||
.substring(0, 16)
|
||||
.split("T");
|
||||
var firstName = "";
|
||||
var lastName = "";
|
||||
firstName = widget.patientQueue[index].first_name;
|
||||
lastName = widget.patientQueue[index].last_name;
|
||||
|
||||
setState(() {
|
||||
idController.text = widget.patientQueue[index].id_no;
|
||||
fnameController.text = firstName;
|
||||
lnameController.text = lastName;
|
||||
dateController.text = appointmentDateTime[0];
|
||||
timeController.text = appointmentDateTime[1];
|
||||
});
|
||||
manageAppointmentPopUp(index);
|
||||
},
|
||||
buttonText: "Manage Appointment",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
//updateAccessAPICall(index, "approved");
|
||||
|
||||
Patient selectedPatient;
|
||||
fetchPatients(widget.patientQueue[index].app_id).then(
|
||||
(result) {
|
||||
setState(() {
|
||||
selectedPatient = result;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context)
|
||||
.pushNamed('/patient-manager/patient',
|
||||
arguments: PatientViewArguments(
|
||||
widget.signedInUser,
|
||||
selectedPatient,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
"business",
|
||||
));
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
buttonText: "View Patient Profile",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.successColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
windowTools: const [],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> addCancelledAppointmentNotificationAPICall(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.patientQueue[index].app_id,
|
||||
"notification_type": "Appointment Cancelled",
|
||||
"notification_message":
|
||||
"Your appointment with ${widget.business!.Name} for the ${widget.patientQueue[index].date_time.replaceAll("T", " ")} has been cancelled.",
|
||||
"action_path": "/access-review",
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 201) {
|
||||
// Navigator.pushNamed(context, '/patient-manager/patient',
|
||||
// arguments: widget.signedInUser);
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed(
|
||||
'/patient-manager',
|
||||
arguments: BusinessArguments(
|
||||
widget.signedInUser,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
),
|
||||
);
|
||||
String message =
|
||||
"The appointment for ${widget.patientQueue[index].first_name} ${widget.patientQueue[index].last_name} at ${widget.patientQueue[index].date_time} has been successfully canceled.";
|
||||
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addRescheduledAppointmentNotificationAPICall(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.patientQueue[index].app_id,
|
||||
"notification_type": "Rescheduled Appointment",
|
||||
"notification_message":
|
||||
"Your appointment with ${widget.business!.Name} for the ${widget.patientQueue[index].date_time.replaceAll("T", " ").substring(0, widget.patientQueue[index].date_time.length - 3)} has been rescheduled to the ${dateController.text} ${timeController.text}.",
|
||||
"action_path": "/access-review",
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 201) {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed(
|
||||
'/patient-manager',
|
||||
arguments: BusinessArguments(
|
||||
widget.signedInUser,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
),
|
||||
);
|
||||
String message =
|
||||
"The appointment for ${widget.patientQueue[index].first_name} ${widget.patientQueue[index].last_name} at ${widget.patientQueue[index].date_time} has been successfully canceled.";
|
||||
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
// Future<void> addAccessExtensionNotificationAPICall(
|
||||
// int index, String revokeDate) 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.patientQueue[index].app_id,
|
||||
// "notification_type": "Access Extension Request",
|
||||
// "notification_message":
|
||||
// "${widget.business!.Name} - access expiry date extension for appointment: ${widget.patientQueue[index].date_time.split("T")[0]}. Expiry Date: from ${widget.patientQueue[index].revoke_date.split("T")[0]} to ${revokeDate.split(" ")[0]}.",
|
||||
// "action_path": "/access-review",
|
||||
// }),
|
||||
// );
|
||||
// if (response.statusCode == 201) {
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pushNamed(
|
||||
// '/patient-manager',
|
||||
// arguments: BusinessArguments(
|
||||
// widget.signedInUser,
|
||||
// widget.businessUser,
|
||||
// widget.business,
|
||||
// ),
|
||||
// );
|
||||
// String message =
|
||||
// "you have successfully requested an extension on the expirey date. The request has been sent tp ${widget.patientQueue[index].first_name} ${widget.patientQueue[index].last_name} to review and approve the request";
|
||||
|
||||
// successPopUp(message);
|
||||
// } else {
|
||||
// internetConnectionPopUp();
|
||||
// }
|
||||
// }
|
||||
|
||||
void manageAppointmentPopUp(int index) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Manage Appointment",
|
||||
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),
|
||||
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),
|
||||
Wrap(
|
||||
runSpacing: 10,
|
||||
spacing: 10,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
//add mihapicall for deleting appointment
|
||||
MIHApiCalls.deleteApointmentAPICall(
|
||||
widget.patientQueue[index].idpatient_queue,
|
||||
widget.patientQueue[index].app_id,
|
||||
widget.patientQueue[index].date_time,
|
||||
BusinessArguments(
|
||||
widget.signedInUser,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
),
|
||||
context,
|
||||
);
|
||||
//updateAccessAPICall(index, "cancelled");
|
||||
},
|
||||
buttonText: "Cancel Appointment",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
MIHApiCalls.updateApointmentAPICall(
|
||||
widget.patientQueue[index].idpatient_queue,
|
||||
widget.patientQueue[index].app_id,
|
||||
widget.business!.Name,
|
||||
widget.patientQueue[index].date_time,
|
||||
dateController.text,
|
||||
timeController.text,
|
||||
BusinessArguments(
|
||||
widget.signedInUser,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
),
|
||||
context,
|
||||
);
|
||||
},
|
||||
buttonText: "Update Appointment",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.successColor(),
|
||||
textColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
windowTools: const [],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Widget displayQueue(int index) {
|
||||
String title =
|
||||
widget.patientQueue[index].date_time.split('T')[1].substring(0, 5);
|
||||
String line234 = "";
|
||||
// var nowDate = DateTime.now();
|
||||
// var expireyDate = DateTime.parse(widget.patientQueue[index].revoke_date);
|
||||
|
||||
line234 +=
|
||||
"Name: ${widget.patientQueue[index].first_name} ${widget.patientQueue[index].last_name}\nID No.: ${widget.patientQueue[index].id_no}\nMedical Aid No: ";
|
||||
if (widget.patientQueue[index].medical_aid_no == "") {
|
||||
line234 += "No Medical Aid";
|
||||
} else {
|
||||
// subtitle +=
|
||||
// "\nMedical Aid No: ";
|
||||
line234 += widget.patientQueue[index].medical_aid_no;
|
||||
}
|
||||
|
||||
// String line5 = "\nAccess Request: ";
|
||||
// String access = "";
|
||||
// if (expireyDate.isBefore(nowDate) &&
|
||||
// widget.patientQueue[index].access != "cacelled") {
|
||||
// access += "EXPIRED";
|
||||
// } else {
|
||||
// access += widget.patientQueue[index].access.toUpperCase();
|
||||
// }
|
||||
// TextSpan accessWithColour;
|
||||
// if (access == "APPROVED") {
|
||||
// accessWithColour = TextSpan(
|
||||
// text: access,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.successColor()));
|
||||
// } else if (access == "PENDING") {
|
||||
// accessWithColour = TextSpan(
|
||||
// text: access,
|
||||
// style: TextStyle(
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.messageTextColor()));
|
||||
// } else {
|
||||
// accessWithColour = TextSpan(
|
||||
// text: access,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.errorColor()));
|
||||
// }
|
||||
// String line6 = "";
|
||||
// line6 +=
|
||||
// "\nAccess Expiration date: ${widget.patientQueue[index].revoke_date.substring(0, 16).replaceAll("T", " ")}";
|
||||
return ListTile(
|
||||
title: Text(
|
||||
"Appointment: $title",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
subtitle: RichText(
|
||||
text: TextSpan(
|
||||
text: line234,
|
||||
style: DefaultTextStyle.of(context).style,
|
||||
// children: [
|
||||
// TextSpan(text: line5),
|
||||
// accessWithColour,
|
||||
// TextSpan(text: line6),
|
||||
// ]
|
||||
),
|
||||
),
|
||||
// Text(
|
||||
// subtitle,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
onTap: () {
|
||||
// var todayDate = DateTime.now();
|
||||
// var revokeDate = DateTime.parse(widget.patientQueue[index].revoke_date);
|
||||
// // print(
|
||||
// // "Todays: $todayDate\nRevoke Date: $revokeDate\nHas revoke date passed: ${revokeDate.isBefore(todayDate)}");
|
||||
// if (revokeDate.isBefore(todayDate)) {
|
||||
// expiredAccessWarning();
|
||||
// } else if (widget.patientQueue[index].access == "approved") {
|
||||
// viewConfirmationPopUp(index);
|
||||
// // Patient selectedPatient;
|
||||
// // fetchPatients(widget.patientQueue[index].app_id).then(
|
||||
// // (result) {
|
||||
// // setState(() {
|
||||
// // selectedPatient = result;
|
||||
// // Navigator.of(context).pushNamed('/patient-manager/patient',
|
||||
// // arguments: PatientViewArguments(
|
||||
// // widget.signedInUser,
|
||||
// // selectedPatient,
|
||||
// // widget.businessUser,
|
||||
// // widget.business,
|
||||
// // "business",
|
||||
// // ));
|
||||
// // });
|
||||
// // },
|
||||
// // );
|
||||
// } else if (widget.patientQueue[index].access == "declined") {
|
||||
// accessDeclinedWarning();
|
||||
// } else if (widget.patientQueue[index].access == "cancelled") {
|
||||
// appointmentCancelledWarning();
|
||||
// } else {
|
||||
viewConfirmationPopUp(index);
|
||||
//noAccessWarning();
|
||||
// }
|
||||
},
|
||||
//leading: getExtendAccessButton(access),
|
||||
//trailing: getExtendAccessButton(access, index),
|
||||
// Icon(
|
||||
// Icons.arrow_forward,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
);
|
||||
}
|
||||
|
||||
bool isAccessExpired(String accessType) {
|
||||
if (accessType == "EXPIRED") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Widget getExtendAccessButton(String accessType, int index) {
|
||||
// if (isAccessExpired(accessType)) {
|
||||
// return IconButton(
|
||||
// icon: const Icon(Icons.cached),
|
||||
// onPressed: () {
|
||||
// setState(() {
|
||||
// daysExtensionController.text = counter.toString();
|
||||
// });
|
||||
// reapplyForAccess(index);
|
||||
// },
|
||||
// );
|
||||
// } else {
|
||||
// return Icon(
|
||||
// Icons.arrow_forward,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// void reapplyForAccess(int index) {
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => MIHWindow(
|
||||
// fullscreen: false,
|
||||
// windowTitle: "Extend Access",
|
||||
// windowTools: const [],
|
||||
// onWindowTapClose: () {
|
||||
// Navigator.pop(context);
|
||||
// },
|
||||
// windowBody: [
|
||||
// Text(
|
||||
// "Current Expiration Date : ${widget.patientQueue[index].revoke_date.replaceAll("T", " ")}",
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// fontSize: 15,
|
||||
// fontWeight: FontWeight.normal,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 5),
|
||||
// Text(
|
||||
// "Select the number of days you would like to extend the access by.",
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// fontSize: 15,
|
||||
// fontWeight: FontWeight.normal,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 5),
|
||||
// Text(
|
||||
// "Once you click \"Apply\", an access review request will be triggered to the patient.",
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// fontSize: 15,
|
||||
// fontWeight: FontWeight.normal,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 30),
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: [
|
||||
// IconButton.filled(
|
||||
// onPressed: () {
|
||||
// if (counter > 0) {
|
||||
// counter--;
|
||||
// setState(() {
|
||||
// daysExtensionController.text = counter.toString();
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
// icon: const Icon(Icons.remove),
|
||||
// ),
|
||||
// const SizedBox(width: 15),
|
||||
// SizedBox(
|
||||
// width: 100,
|
||||
// child: MIHTextField(
|
||||
// controller: daysExtensionController,
|
||||
// hintText: "Days",
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(width: 15),
|
||||
// IconButton.filled(
|
||||
// onPressed: () {
|
||||
// counter++;
|
||||
// setState(() {
|
||||
// daysExtensionController.text = counter.toString();
|
||||
// });
|
||||
// },
|
||||
// icon: const Icon(Icons.add),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// const SizedBox(height: 30),
|
||||
// SizedBox(
|
||||
// width: 300,
|
||||
// height: 50,
|
||||
// child: MIHButton(
|
||||
// onTap: () {
|
||||
// print(
|
||||
// "Revoke Date (String): ${widget.patientQueue[index].revoke_date}");
|
||||
// var revokeDate = DateTime.parse(widget
|
||||
// .patientQueue[index].revoke_date
|
||||
// .replaceAll("T", " "));
|
||||
// var newRevokeDate = revokeDate.add(
|
||||
// Duration(days: int.parse(daysExtensionController.text)));
|
||||
// print("Revoke Date (DateTime): $revokeDate");
|
||||
// print("New Revoke Date (DateTime): $newRevokeDate");
|
||||
// print(
|
||||
// "${widget.business!.Name} would like to extend the access expirey date for your appointment on the ${widget.patientQueue[index].date_time}.\nNew Expirey Date: $revokeDate",
|
||||
// );
|
||||
// extendAccessAPICall(index, "$newRevokeDate");
|
||||
// },
|
||||
// buttonText: "Apply",
|
||||
// buttonColor:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
void noAccessWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "No Access");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void accessDeclinedWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "Access Declined");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void appointmentCancelledWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "Appointment Canelled");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void expiredAccessWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHWarningMessage(warningType: "Expired Access");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
daysExtensionController.dispose();
|
||||
dateController.dispose();
|
||||
timeController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.separated(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
separatorBuilder: (BuildContext context, index) {
|
||||
return Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
);
|
||||
},
|
||||
itemCount: widget.patientQueue.length,
|
||||
itemBuilder: (context, index) {
|
||||
//final patient = widget.patients[index].id_no.contains(widget.searchString);
|
||||
//print(index);
|
||||
return displayQueue(index);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
304
Frontend/lib/mih_packages/patient_profile/full_screen_file.dart
Normal file
304
Frontend/lib/mih_packages/patient_profile/full_screen_file.dart
Normal file
@@ -0,0 +1,304 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:syncfusion_flutter_core/theme.dart';
|
||||
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
|
||||
import "package:universal_html/html.dart" as html;
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:printing/printing.dart';
|
||||
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
|
||||
class FullScreenFileViewer extends StatefulWidget {
|
||||
final FileViewArguments arguments;
|
||||
const FullScreenFileViewer({
|
||||
super.key,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<FullScreenFileViewer> createState() => _FullScreenFileViewerState();
|
||||
}
|
||||
|
||||
class _FullScreenFileViewerState extends State<FullScreenFileViewer> {
|
||||
late PdfViewerController pdfViewerController = PdfViewerController();
|
||||
int currentPageCount = 0;
|
||||
int currentPage = 0;
|
||||
double startZoomLevel = 1.0;
|
||||
double zoomOut = 0;
|
||||
|
||||
String getExtType(String path) {
|
||||
//print(pdfLink.split(".")[1]);
|
||||
return path.split(".").last;
|
||||
}
|
||||
|
||||
String getFileName(String path) {
|
||||
//print(pdfLink.split(".")[1]);
|
||||
return path.split("/").last;
|
||||
}
|
||||
|
||||
void onPageSelect() {
|
||||
setState(() {
|
||||
currentPage = pdfViewerController.pageNumber;
|
||||
});
|
||||
}
|
||||
|
||||
void printDocument() async {
|
||||
print("Printing ${widget.arguments.path.split("/").last}");
|
||||
http.Response response = await http.get(Uri.parse(widget.arguments.link));
|
||||
var pdfData = response.bodyBytes;
|
||||
Navigator.of(context).pushNamed(
|
||||
'/file-veiwer/print-preview',
|
||||
arguments: pdfData,
|
||||
);
|
||||
// Navigator.of(context).push(
|
||||
// MaterialPageRoute(
|
||||
// builder: (context) => PdfPreview(
|
||||
// initialPageFormat: PdfPageFormat.a4,
|
||||
// build: (format) => pdfData,
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// try {
|
||||
// await Printing.layoutPdf(
|
||||
// onLayout: (PdfPageFormat format) async => pdfData);
|
||||
// } on Exception catch (_) {
|
||||
// print("Print Error");
|
||||
// }
|
||||
}
|
||||
|
||||
void shareDocument() async {
|
||||
http.Response response = await http.get(Uri.parse(widget.arguments.link));
|
||||
var pdfData = response.bodyBytes;
|
||||
await Printing.sharePdf(
|
||||
bytes: pdfData, filename: widget.arguments.path.split("/").last);
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(
|
||||
Icons.fullscreen_exit,
|
||||
),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader(double width) {
|
||||
bool isPDF;
|
||||
if (getExtType(widget.arguments.path).toLowerCase() == "pdf") {
|
||||
isPDF = true;
|
||||
} else {
|
||||
isPDF = false;
|
||||
}
|
||||
return MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.end,
|
||||
headerItems: [
|
||||
Visibility(
|
||||
visible: isPDF,
|
||||
child: IconButton(
|
||||
iconSize: 30,
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
pdfViewerController.previousPage();
|
||||
//print(pdfViewerController.);
|
||||
//if (pdfViewerController.pageNumber > 1) {
|
||||
setState(() {
|
||||
currentPage = pdfViewerController.pageNumber;
|
||||
});
|
||||
// }
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.arrow_back,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: isPDF,
|
||||
child: Text(
|
||||
"$currentPage / $currentPageCount",
|
||||
style: const TextStyle(fontSize: 20),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: isPDF,
|
||||
child: IconButton(
|
||||
iconSize: 30,
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
pdfViewerController.nextPage();
|
||||
//print(pdfViewerController.pageNumber);
|
||||
//if (pdfViewerController.pageNumber < currentPageCount) {
|
||||
setState(() {
|
||||
currentPage = pdfViewerController.pageNumber;
|
||||
});
|
||||
//}
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.arrow_forward,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: isPDF,
|
||||
child: IconButton(
|
||||
iconSize: 30,
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
if (zoomOut > 0) {
|
||||
setState(() {
|
||||
zoomOut = zoomOut - 100;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
pdfViewerController.zoomLevel = startZoomLevel + 0.25;
|
||||
startZoomLevel = pdfViewerController.zoomLevel;
|
||||
});
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.zoom_in,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: isPDF,
|
||||
child: IconButton(
|
||||
iconSize: 30,
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
if (pdfViewerController.zoomLevel > 1) {
|
||||
setState(() {
|
||||
pdfViewerController.zoomLevel = startZoomLevel - 0.25;
|
||||
startZoomLevel = pdfViewerController.zoomLevel;
|
||||
});
|
||||
} else {
|
||||
if (zoomOut < (width - 100)) {
|
||||
setState(() {
|
||||
zoomOut = zoomOut + 100;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.zoom_out,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
// IconButton(
|
||||
// iconSize: 30,
|
||||
// padding: const EdgeInsets.all(0),
|
||||
// onPressed: () {
|
||||
// printDocument();
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.print,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// ),
|
||||
// ),
|
||||
IconButton(
|
||||
iconSize: 30,
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
html.window.open(
|
||||
widget.arguments.link,
|
||||
// '${AppEnviroment.baseFileUrl}/mih/$filePath',
|
||||
'download');
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.download,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody(double width, double height) {
|
||||
Widget fileViewer;
|
||||
if (getExtType(widget.arguments.path).toLowerCase() == "pdf") {
|
||||
fileViewer = SizedBox(
|
||||
width: width - zoomOut,
|
||||
height: height - 70,
|
||||
child: SfPdfViewerTheme(
|
||||
data: SfPdfViewerThemeData(
|
||||
backgroundColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
child: SfPdfViewer.network(
|
||||
widget.arguments.link,
|
||||
controller: pdfViewerController,
|
||||
initialZoomLevel: startZoomLevel,
|
||||
pageSpacing: 2,
|
||||
maxZoomLevel: 5,
|
||||
interactionMode: PdfInteractionMode.pan,
|
||||
onDocumentLoaded: (details) {
|
||||
setState(() {
|
||||
currentPage = pdfViewerController.pageNumber;
|
||||
currentPageCount = pdfViewerController.pageCount;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
fileViewer = SizedBox(
|
||||
width: width,
|
||||
height: height - 70,
|
||||
child: InteractiveViewer(
|
||||
maxScale: 5.0,
|
||||
//minScale: 0.,
|
||||
child: Image.network(widget.arguments.link),
|
||||
),
|
||||
);
|
||||
}
|
||||
return MIHBody(
|
||||
borderOn: false,
|
||||
bodyItems: [
|
||||
fileViewer,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
pdfViewerController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
//pdfViewerController = widget.arguments.pdfViewerController!;
|
||||
pdfViewerController.addListener(onPageSelect);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Size size = MediaQuery.sizeOf(context);
|
||||
double width = size.width;
|
||||
double height = size.height;
|
||||
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(width),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(width, height),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
}
|
||||
}
|
||||
443
Frontend/lib/mih_packages/patient_profile/patient_add.dart
Normal file
443
Frontend/lib/mih_packages/patient_profile/patient_add.dart
Normal file
@@ -0,0 +1,443 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.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_env/env.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
|
||||
class AddPatient extends StatefulWidget {
|
||||
final AppUser signedInUser;
|
||||
|
||||
const AddPatient({
|
||||
super.key,
|
||||
required this.signedInUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AddPatient> createState() => _AddPatientState();
|
||||
}
|
||||
|
||||
class _AddPatientState extends State<AddPatient> {
|
||||
final idController = TextEditingController();
|
||||
final fnameController = TextEditingController();
|
||||
final lnameController = TextEditingController();
|
||||
final cellController = TextEditingController();
|
||||
final emailController = TextEditingController();
|
||||
final medNoController = TextEditingController();
|
||||
final medNameController = TextEditingController();
|
||||
final medSchemeController = TextEditingController();
|
||||
final addressController = TextEditingController();
|
||||
final medAidController = TextEditingController();
|
||||
final medMainMemController = TextEditingController();
|
||||
final medAidCodeController = TextEditingController();
|
||||
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
late int futureDocOfficeId;
|
||||
late bool medRequired;
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
bool isFieldsFilled() {
|
||||
if (medRequired) {
|
||||
if (idController.text.isEmpty ||
|
||||
fnameController.text.isEmpty ||
|
||||
lnameController.text.isEmpty ||
|
||||
cellController.text.isEmpty ||
|
||||
emailController.text.isEmpty ||
|
||||
medNoController.text.isEmpty ||
|
||||
medNameController.text.isEmpty ||
|
||||
medSchemeController.text.isEmpty ||
|
||||
addressController.text.isEmpty ||
|
||||
medAidController.text.isEmpty ||
|
||||
medMainMemController.text.isEmpty ||
|
||||
medAidCodeController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (idController.text.isEmpty ||
|
||||
fnameController.text.isEmpty ||
|
||||
lnameController.text.isEmpty ||
|
||||
cellController.text.isEmpty ||
|
||||
emailController.text.isEmpty ||
|
||||
addressController.text.isEmpty ||
|
||||
medAidController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addPatientAPICall() async {
|
||||
var response = await http.post(
|
||||
Uri.parse("$baseAPI/patients/insert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"id_no": idController.text,
|
||||
"first_name": fnameController.text,
|
||||
"last_name": lnameController.text,
|
||||
"email": emailController.text,
|
||||
"cell_no": cellController.text,
|
||||
"medical_aid": medAidController.text,
|
||||
"medical_aid_main_member": medMainMemController.text,
|
||||
"medical_aid_no": medNoController.text,
|
||||
"medical_aid_code": medAidCodeController.text,
|
||||
"medical_aid_name": medNameController.text,
|
||||
"medical_aid_scheme": medSchemeController.text,
|
||||
"address": addressController.text,
|
||||
"app_id": widget.signedInUser.app_id,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 201) {
|
||||
Navigator.of(context).popAndPushNamed('/patient-profile',
|
||||
arguments: PatientViewArguments(
|
||||
widget.signedInUser, null, null, null, "personal"));
|
||||
String message =
|
||||
"${fnameController.text} ${lnameController.text} patient profiole has been successfully added!\n";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
void internetConnectionPopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Internet Connection");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void messagePopUp(error) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(error),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void successPopUp(String message) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return MIHSuccessMessage(
|
||||
successType: "Success",
|
||||
successMessage: message,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void isRequired() {
|
||||
//print("listerner triggered");
|
||||
if (medAidController.text == "Yes") {
|
||||
setState(() {
|
||||
medRequired = true;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
medRequired = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget displayForm() {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
"Personal Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22.0,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: idController,
|
||||
hintText: "13 digit ID Number or Passport",
|
||||
editable: true,
|
||||
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: "Last Name",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: cellController,
|
||||
hintText: "Cell Number",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: emailController,
|
||||
hintText: "Email",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: addressController,
|
||||
hintText: "Address",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
Text(
|
||||
"Medical Aid Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22.0,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: medAidController,
|
||||
hintText: "Medical Aid",
|
||||
editable: true,
|
||||
onSelect: (_) {
|
||||
isRequired();
|
||||
},
|
||||
required: true,
|
||||
dropdownOptions: const ["Yes", "No"],
|
||||
),
|
||||
Visibility(
|
||||
visible: medRequired,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: medMainMemController,
|
||||
hintText: "Main Member",
|
||||
editable: medRequired,
|
||||
required: medRequired,
|
||||
dropdownOptions: const ["Yes", "No"],
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: medNoController,
|
||||
hintText: "Medical Aid No.",
|
||||
editable: medRequired,
|
||||
required: medRequired,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: medAidCodeController,
|
||||
hintText: "Medical Aid Code",
|
||||
editable: medRequired,
|
||||
required: medRequired,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: medNameController,
|
||||
hintText: "Medical Aid Name",
|
||||
editable: medRequired,
|
||||
required: medRequired,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: medSchemeController,
|
||||
hintText: "Medical Aid Scheme",
|
||||
editable: medRequired,
|
||||
required: medRequired,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30.0),
|
||||
SizedBox(
|
||||
width: 450.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
submitForm();
|
||||
},
|
||||
buttonText: "Add",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void submitForm() {
|
||||
if (isFieldsFilled()) {
|
||||
addPatientAPICall();
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"Add Patient Details",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: true,
|
||||
bodyItems: [
|
||||
KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
submitForm();
|
||||
}
|
||||
},
|
||||
child: displayForm(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
idController.dispose();
|
||||
fnameController.dispose();
|
||||
lnameController.dispose();
|
||||
cellController.dispose();
|
||||
emailController.dispose();
|
||||
medNoController.dispose();
|
||||
medNameController.dispose();
|
||||
medSchemeController.dispose();
|
||||
addressController.dispose();
|
||||
medAidController.dispose();
|
||||
medMainMemController.dispose();
|
||||
medAidCodeController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
medAidController.addListener(isRequired);
|
||||
setState(() {
|
||||
fnameController.text = widget.signedInUser.fname;
|
||||
lnameController.text = widget.signedInUser.lname;
|
||||
emailController.text = widget.signedInUser.email;
|
||||
medAidController.text = "No";
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
// return Scaffold(
|
||||
// // appBar: const MIHAppBar(
|
||||
// // barTitle: "Add Patient",
|
||||
// // propicFile: null,
|
||||
// // ),
|
||||
// //drawer: MIHAppDrawer(signedInUser: widget.signedInUser),
|
||||
// body: SafeArea(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// KeyboardListener(
|
||||
// focusNode: _focusNode,
|
||||
// autofocus: true,
|
||||
// onKeyEvent: (event) async {
|
||||
// if (event is KeyDownEvent &&
|
||||
// event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
// submitForm();
|
||||
// }
|
||||
// },
|
||||
// child: displayForm(),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 10,
|
||||
// left: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// icon: const Icon(Icons.arrow_back),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
}
|
||||
298
Frontend/lib/mih_packages/patient_profile/patient_details.dart
Normal file
298
Frontend/lib/mih_packages/patient_profile/patient_details.dart
Normal file
@@ -0,0 +1,298 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:patient_manager/mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../main.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
import '../../mih_objects/patients.dart';
|
||||
|
||||
class PatientDetails extends StatefulWidget {
|
||||
final AppUser signedInUser;
|
||||
final Patient selectedPatient;
|
||||
final String type;
|
||||
const PatientDetails({
|
||||
super.key,
|
||||
required this.signedInUser,
|
||||
required this.selectedPatient,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PatientDetails> createState() => _PatientDetailsState();
|
||||
}
|
||||
|
||||
class _PatientDetailsState extends State<PatientDetails> {
|
||||
final idController = TextEditingController();
|
||||
final fnameController = TextEditingController();
|
||||
final lnameController = TextEditingController();
|
||||
final cellController = TextEditingController();
|
||||
final emailController = TextEditingController();
|
||||
final medNoController = TextEditingController();
|
||||
final medNameController = TextEditingController();
|
||||
final medSchemeController = TextEditingController();
|
||||
final addressController = TextEditingController();
|
||||
final medAidController = TextEditingController();
|
||||
final medMainMemController = TextEditingController();
|
||||
final medAidCodeController = TextEditingController();
|
||||
double? headingFontSize = 35.0;
|
||||
double? bodyFonstSize = 20.0;
|
||||
double textFieldWidth = 400.0;
|
||||
late String medAid;
|
||||
|
||||
Widget getPatientDetailsField() {
|
||||
return Wrap(
|
||||
spacing: 15,
|
||||
runSpacing: 10,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: idController,
|
||||
hintText: "ID No.",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: fnameController,
|
||||
hintText: "Name",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: lnameController,
|
||||
hintText: "Surname",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: cellController,
|
||||
hintText: "Cell No.",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: emailController,
|
||||
hintText: "Email",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: addressController,
|
||||
hintText: "Address",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget getMedAidDetailsFields() {
|
||||
List<Widget> medAidDet = [];
|
||||
medAidDet.add(SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: medAidController,
|
||||
hintText: "Medical Aid",
|
||||
editable: false,
|
||||
required: false),
|
||||
));
|
||||
bool req;
|
||||
if (medAid == "Yes") {
|
||||
req = true;
|
||||
} else {
|
||||
req = false;
|
||||
}
|
||||
medAidDet.addAll([
|
||||
Visibility(
|
||||
visible: req,
|
||||
child: SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: medMainMemController,
|
||||
hintText: "Main Member",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
),
|
||||
//const SizedBox(height: 10.0),
|
||||
Visibility(
|
||||
visible: req,
|
||||
child: SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: medNoController,
|
||||
hintText: "No.",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
),
|
||||
//const SizedBox(height: 10.0),
|
||||
Visibility(
|
||||
visible: req,
|
||||
child: SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: medAidCodeController,
|
||||
hintText: "Code",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
),
|
||||
//const SizedBox(height: 10.0),
|
||||
Visibility(
|
||||
visible: req,
|
||||
child: SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: medNameController,
|
||||
hintText: "Name",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
),
|
||||
//const SizedBox(height: 10.0),
|
||||
Visibility(
|
||||
visible: req,
|
||||
child: SizedBox(
|
||||
width: textFieldWidth,
|
||||
child: MIHTextField(
|
||||
controller: medSchemeController,
|
||||
hintText: "Scheme",
|
||||
editable: false,
|
||||
required: false),
|
||||
),
|
||||
),
|
||||
//),
|
||||
]);
|
||||
|
||||
return Wrap(
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
children: medAidDet,
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> setIcons() {
|
||||
if (widget.type == "personal") {
|
||||
return [
|
||||
Text(
|
||||
"Personal Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
alignment: Alignment.topRight,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushNamed('/patient-profile/edit',
|
||||
arguments: PatientEditArguments(
|
||||
widget.signedInUser, widget.selectedPatient));
|
||||
},
|
||||
)
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
Text(
|
||||
"Patient Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
idController.dispose();
|
||||
fnameController.dispose();
|
||||
lnameController.dispose();
|
||||
cellController.dispose();
|
||||
emailController.dispose();
|
||||
medNameController.dispose();
|
||||
medNoController.dispose();
|
||||
medSchemeController.dispose();
|
||||
addressController.dispose();
|
||||
medAidController.dispose();
|
||||
medMainMemController.dispose();
|
||||
medAidCodeController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
setState(() {
|
||||
idController.value = TextEditingValue(text: widget.selectedPatient.id_no);
|
||||
fnameController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.first_name);
|
||||
lnameController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.last_name);
|
||||
cellController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.cell_no);
|
||||
emailController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.email);
|
||||
medNameController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.medical_aid_name);
|
||||
medNoController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.medical_aid_no);
|
||||
medSchemeController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.medical_aid_scheme);
|
||||
addressController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.address);
|
||||
medAidController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.medical_aid);
|
||||
medMainMemController.value = TextEditingValue(
|
||||
text: widget.selectedPatient.medical_aid_main_member);
|
||||
medAidCodeController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.medical_aid_code);
|
||||
medAid = widget.selectedPatient.medical_aid;
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
//crossAxisAlignment: ,
|
||||
children: setIcons(),
|
||||
),
|
||||
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
const SizedBox(height: 10),
|
||||
getPatientDetailsField(),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"Medical Aid Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
const SizedBox(height: 10),
|
||||
getMedAidDetailsFields(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
721
Frontend/lib/mih_packages/patient_profile/patient_edit.dart
Normal file
721
Frontend/lib/mih_packages/patient_profile/patient_edit.dart
Normal file
@@ -0,0 +1,721 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.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_env/env.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
import '../../mih_objects/patients.dart';
|
||||
|
||||
class EditPatient extends StatefulWidget {
|
||||
final Patient selectedPatient;
|
||||
final AppUser signedInUser;
|
||||
const EditPatient({
|
||||
super.key,
|
||||
required this.selectedPatient,
|
||||
required this.signedInUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<EditPatient> createState() => _EditPatientState();
|
||||
}
|
||||
|
||||
class _EditPatientState extends State<EditPatient> {
|
||||
var idController = TextEditingController();
|
||||
final fnameController = TextEditingController();
|
||||
final lnameController = TextEditingController();
|
||||
final cellController = TextEditingController();
|
||||
final emailController = TextEditingController();
|
||||
final medNoController = TextEditingController();
|
||||
final medNameController = TextEditingController();
|
||||
final medSchemeController = TextEditingController();
|
||||
final addressController = TextEditingController();
|
||||
final medAidController = TextEditingController();
|
||||
final medMainMemController = TextEditingController();
|
||||
final medAidCodeController = TextEditingController();
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
final docOfficeIdApiUrl = "${AppEnviroment.baseApiUrl}/users/profile/";
|
||||
final apiUrlEdit = "${AppEnviroment.baseApiUrl}/patients/update/";
|
||||
final apiUrlDelete = "${AppEnviroment.baseApiUrl}/patients/delete/";
|
||||
|
||||
late int futureDocOfficeId;
|
||||
late String userEmail;
|
||||
late bool medRequired;
|
||||
|
||||
late double width;
|
||||
late double height;
|
||||
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
// Future getOfficeIdByUser(String endpoint) async {
|
||||
// final response = await http.get(Uri.parse(endpoint));
|
||||
// if (response.statusCode == 200) {
|
||||
// String body = response.body;
|
||||
// var decodedData = jsonDecode(body);
|
||||
// AppUser u = AppUser.fromJson(decodedData as Map<String, dynamic>);
|
||||
// setState(() {
|
||||
// //futureDocOfficeId = u.docOffice_id;
|
||||
// //print(futureDocOfficeId);
|
||||
// });
|
||||
// } else {
|
||||
// internetConnectionPopUp();
|
||||
// throw Exception('failed to load patients');
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<void> updatePatientApiCall() async {
|
||||
//print("Here1");
|
||||
//userEmail = getLoginUserEmail() as String;
|
||||
//print(userEmail);
|
||||
//print("Here2");
|
||||
//await getOfficeIdByUser(docOfficeIdApiUrl + userEmail);
|
||||
//print(futureDocOfficeId.toString());
|
||||
//print("Here3");
|
||||
var response = await http.put(
|
||||
Uri.parse(apiUrlEdit),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"id_no": idController.text,
|
||||
"first_name": fnameController.text,
|
||||
"last_name": lnameController.text,
|
||||
"email": emailController.text,
|
||||
"cell_no": cellController.text,
|
||||
"medical_aid": medAidController.text,
|
||||
"medical_aid_main_member": medMainMemController.text,
|
||||
"medical_aid_no": medNoController.text,
|
||||
"medical_aid_code": medAidCodeController.text,
|
||||
"medical_aid_name": medNameController.text,
|
||||
"medical_aid_scheme": medSchemeController.text,
|
||||
"address": addressController.text,
|
||||
"app_id": widget.selectedPatient.app_id,
|
||||
}),
|
||||
);
|
||||
// print("Here4");
|
||||
// print(response.statusCode);
|
||||
if (response.statusCode == 200) {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed('/patient-profile',
|
||||
arguments: PatientViewArguments(
|
||||
widget.signedInUser, null, null, null, "personal"));
|
||||
//Navigator.of(context).pushNamed('/');
|
||||
String message =
|
||||
"${fnameController.text} ${lnameController.text}'s information has been updated successfully! Their medical records and details are now current.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deletePatientApiCall() async {
|
||||
//print("Here1");
|
||||
//userEmail = getLoginUserEmail() as String;
|
||||
//print(userEmail);
|
||||
//print("Here2");
|
||||
//await getOfficeIdByUser(docOfficeIdApiUrl + userEmail);
|
||||
//print("Office ID: ${futureDocOfficeId.toString()}");
|
||||
//print("OPatient ID No: ${idController.text}");
|
||||
//print("Here3");
|
||||
var response = await http.delete(
|
||||
Uri.parse(apiUrlDelete),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(
|
||||
<String, dynamic>{"app_id": widget.selectedPatient.app_id}),
|
||||
);
|
||||
//print("Here4");
|
||||
//print(response.statusCode);
|
||||
if (response.statusCode == 200) {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).popAndPushNamed('/patient-profile',
|
||||
arguments: PatientViewArguments(
|
||||
widget.signedInUser, null, null, null, "personal"));
|
||||
String message =
|
||||
"${fnameController.text} ${lnameController.text}'s record has been deleted successfully. This means it will no longer be visible in patient manager and cannot be used for future appointments.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getLoginUserEmail() async {
|
||||
var uid = await SuperTokens.getUserId();
|
||||
var response = await http.get(Uri.parse("$baseAPI/user/$uid"));
|
||||
if (response.statusCode == 200) {
|
||||
var user = jsonDecode(response.body);
|
||||
userEmail = user["email"];
|
||||
}
|
||||
}
|
||||
|
||||
void messagePopUp(error) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(error),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void internetConnectionPopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Internet Connection");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void deletePatientPopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => Dialog(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
width: 700.0,
|
||||
height: (height / 3) * 2,
|
||||
decoration: BoxDecoration(
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
border: Border.all(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
width: 5.0),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
//mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.warning_amber_rounded,
|
||||
size: 100,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
"Are you sure you want to delete this?",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 25.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25.0),
|
||||
child: Text(
|
||||
"This action is permanent! Deleting ${fnameController.text} ${lnameController.text} will remove him\\her from your account. You won't be able to recover it once it's gone.",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25.0),
|
||||
child: Text(
|
||||
"Here's what you'll be deleting:",
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 20.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25.0),
|
||||
child: SizedBox(
|
||||
width: 450,
|
||||
child: Text(
|
||||
"1) Patient Profile Information.\n2) Patient Notes\n3) Patient Files.",
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: deletePatientApiCall,
|
||||
buttonText: "Delete",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.primaryColor(),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
right: 5,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.close,
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void successPopUp(String message) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return MIHSuccessMessage(
|
||||
successType: "Success",
|
||||
successMessage: message,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool isFieldsFilled() {
|
||||
if (medRequired) {
|
||||
if (idController.text.isEmpty ||
|
||||
fnameController.text.isEmpty ||
|
||||
lnameController.text.isEmpty ||
|
||||
cellController.text.isEmpty ||
|
||||
emailController.text.isEmpty ||
|
||||
medNoController.text.isEmpty ||
|
||||
medNameController.text.isEmpty ||
|
||||
medSchemeController.text.isEmpty ||
|
||||
addressController.text.isEmpty ||
|
||||
medAidController.text.isEmpty ||
|
||||
medMainMemController.text.isEmpty ||
|
||||
medAidCodeController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (idController.text.isEmpty ||
|
||||
fnameController.text.isEmpty ||
|
||||
lnameController.text.isEmpty ||
|
||||
cellController.text.isEmpty ||
|
||||
emailController.text.isEmpty ||
|
||||
addressController.text.isEmpty ||
|
||||
medAidController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void isRequired() {
|
||||
//print("listerner triggered");
|
||||
if (medAidController.text == "Yes") {
|
||||
setState(() {
|
||||
medRequired = true;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
medRequired = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget displayForm() {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Personal Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22.0,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
//alignment: Alignment.topRight,
|
||||
onPressed: () {
|
||||
deletePatientPopUp();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: idController,
|
||||
hintText: "13 digit ID Number or Passport",
|
||||
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: "Last Name",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: cellController,
|
||||
hintText: "Cell Number",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: emailController,
|
||||
hintText: "Email",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: addressController,
|
||||
hintText: "Address",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
Text(
|
||||
"Medical Aid Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22.0,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: medAidController,
|
||||
hintText: "Medical Aid",
|
||||
onSelect: (selected) {
|
||||
if (selected == "Yes") {
|
||||
setState(() {
|
||||
medRequired = true;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
medRequired = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
editable: true,
|
||||
required: true,
|
||||
dropdownOptions: const ["Yes", "No"],
|
||||
),
|
||||
Visibility(
|
||||
visible: medRequired,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: medMainMemController,
|
||||
hintText: "Main Member.",
|
||||
editable: medRequired,
|
||||
required: medRequired,
|
||||
dropdownOptions: const ["Yes", "No"],
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: medNoController,
|
||||
hintText: "Medical Aid No.",
|
||||
editable: medRequired,
|
||||
required: medRequired,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: medAidCodeController,
|
||||
hintText: "Medical Aid Code",
|
||||
editable: medRequired,
|
||||
required: medRequired,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: medNameController,
|
||||
hintText: "Medical Aid Name",
|
||||
editable: medRequired,
|
||||
required: medRequired,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: medSchemeController,
|
||||
hintText: "Medical Aid Scheme",
|
||||
editable: medRequired,
|
||||
required: medRequired,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30.0),
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
height: 50.0,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
submitForm();
|
||||
},
|
||||
buttonText: "Update",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void submitForm() {
|
||||
if (isFieldsFilled()) {
|
||||
if (!medRequired) {
|
||||
setState(() {
|
||||
medMainMemController.text = "";
|
||||
medNoController.text = "";
|
||||
medAidCodeController.text = "";
|
||||
medNameController.text = "";
|
||||
medSchemeController.text = "";
|
||||
});
|
||||
}
|
||||
updatePatientApiCall();
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"Edit Patient Details",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: true,
|
||||
bodyItems: [
|
||||
KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
submitForm();
|
||||
}
|
||||
},
|
||||
child: displayForm(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
idController.dispose();
|
||||
fnameController.dispose();
|
||||
lnameController.dispose();
|
||||
cellController.dispose();
|
||||
emailController.dispose();
|
||||
medNoController.dispose();
|
||||
medNameController.dispose();
|
||||
medSchemeController.dispose();
|
||||
addressController.dispose();
|
||||
medAidController.dispose();
|
||||
medMainMemController.dispose();
|
||||
medAidCodeController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
getLoginUserEmail();
|
||||
medAidController.addListener(isRequired);
|
||||
setState(() {
|
||||
idController.value = TextEditingValue(text: widget.selectedPatient.id_no);
|
||||
fnameController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.first_name);
|
||||
lnameController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.last_name);
|
||||
cellController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.cell_no);
|
||||
emailController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.email);
|
||||
medNameController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.medical_aid_name);
|
||||
medNoController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.medical_aid_no);
|
||||
medSchemeController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.medical_aid_scheme);
|
||||
addressController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.address);
|
||||
medAidController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.medical_aid);
|
||||
medMainMemController.value = TextEditingValue(
|
||||
text: widget.selectedPatient.medical_aid_main_member);
|
||||
medAidCodeController.value =
|
||||
TextEditingValue(text: widget.selectedPatient.medical_aid_code);
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var size = MediaQuery.of(context).size;
|
||||
setState(() {
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
});
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
// return Scaffold(
|
||||
// // appBar: const MIHAppBar(
|
||||
// // barTitle: "Edit Patient",
|
||||
// // propicFile: null,
|
||||
// // ),
|
||||
// body: SafeArea(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// KeyboardListener(
|
||||
// focusNode: _focusNode,
|
||||
// autofocus: true,
|
||||
// onKeyEvent: (event) async {
|
||||
// if (event is KeyDownEvent &&
|
||||
// event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
// submitForm();
|
||||
// }
|
||||
// },
|
||||
// child: displayForm(),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 10,
|
||||
// left: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// icon: const Icon(Icons.arrow_back),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 10,
|
||||
// right: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// icon: const Icon(Icons.delete),
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// //alignment: Alignment.topRight,
|
||||
// onPressed: () {
|
||||
// deletePatientPopUp();
|
||||
// },
|
||||
// ))
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
}
|
||||
543
Frontend/lib/mih_packages/patient_profile/patient_files.dart
Normal file
543
Frontend/lib/mih_packages/patient_profile/patient_files.dart
Normal file
@@ -0,0 +1,543 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
import 'package:http/http.dart' as http2;
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
|
||||
import '../../mih_components/med_cert_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_file_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_window.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/business.dart';
|
||||
import '../../mih_objects/business_user.dart';
|
||||
import '../../mih_objects/files.dart';
|
||||
import '../../mih_objects/patients.dart';
|
||||
import 'builder/build_files_list.dart';
|
||||
import 'prescip_input.dart';
|
||||
|
||||
class PatientFiles extends StatefulWidget {
|
||||
final int patientIndex;
|
||||
final Patient selectedPatient;
|
||||
final AppUser signedInUser;
|
||||
final Business? business;
|
||||
final BusinessUser? businessUser;
|
||||
final String type;
|
||||
|
||||
const PatientFiles({
|
||||
super.key,
|
||||
required this.patientIndex,
|
||||
required this.selectedPatient,
|
||||
required this.signedInUser,
|
||||
required this.business,
|
||||
required this.businessUser,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PatientFiles> createState() => _PatientFilesState();
|
||||
}
|
||||
|
||||
class _PatientFilesState extends State<PatientFiles> {
|
||||
String endpointFiles = "${AppEnviroment.baseApiUrl}/files/patients/";
|
||||
String endpointUser = "${AppEnviroment.baseApiUrl}/users/profile/";
|
||||
String endpointGenFiles =
|
||||
"${AppEnviroment.baseApiUrl}/files/generate/med-cert/";
|
||||
String endpointFileUpload = "${AppEnviroment.baseApiUrl}/files/upload/file/";
|
||||
String endpointInsertFiles = "${AppEnviroment.baseApiUrl}/files/insert/";
|
||||
|
||||
final startDateController = TextEditingController();
|
||||
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<List<PFile>> futueFiles;
|
||||
late String userEmail = "";
|
||||
late PlatformFile selected;
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
Future<void> generateMedCert() async {
|
||||
//start loading circle
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
var response1 = await http.post(
|
||||
Uri.parse("${AppEnviroment.baseApiUrl}/minio/generate/med-cert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"app_id": widget.selectedPatient.app_id,
|
||||
"fullName":
|
||||
"${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}",
|
||||
"id_no": widget.selectedPatient.id_no,
|
||||
"docfname":
|
||||
"DR. ${widget.signedInUser.fname} ${widget.signedInUser.lname}",
|
||||
"startDate": startDateController.text,
|
||||
"busName": widget.business!.Name,
|
||||
"busAddr": "*TO BE ADDED IN THE FUTURE*",
|
||||
"busNo": widget.business!.contact_no,
|
||||
"busEmail": widget.business!.bus_email,
|
||||
"endDate": endDateTextController.text,
|
||||
"returnDate": retDateTextController.text,
|
||||
"logo_path": widget.business!.logo_path,
|
||||
"sig_path": widget.businessUser!.sig_path,
|
||||
}),
|
||||
);
|
||||
//print(response1.statusCode);
|
||||
DateTime now = new DateTime.now();
|
||||
DateTime date = new DateTime(now.year, now.month, now.day);
|
||||
String fileName =
|
||||
"Med-Cert-${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}-${date.toString().substring(0, 10)}.pdf";
|
||||
if (response1.statusCode == 200) {
|
||||
var response2 = await http.post(
|
||||
Uri.parse("${AppEnviroment.baseApiUrl}/files/insert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"file_path":
|
||||
"${widget.selectedPatient.app_id}/patient_files/$fileName",
|
||||
"file_name": fileName,
|
||||
"app_id": widget.selectedPatient.app_id
|
||||
}),
|
||||
);
|
||||
//print(response2.statusCode);
|
||||
if (response2.statusCode == 201) {
|
||||
setState(() {
|
||||
startDateController.clear();
|
||||
endDateTextController.clear();
|
||||
retDateTextController.clear();
|
||||
futueFiles = fetchFiles();
|
||||
});
|
||||
// end loading circle
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
String message =
|
||||
"The medical certificate $fileName has been successfully generated and added to ${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}'s record. You can now access and download it for their use.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> uploadSelectedFile(PlatformFile file) async {
|
||||
//var strem = new http.ByteStream.fromBytes(file.bytes.)
|
||||
//start loading circle
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
var token = await SuperTokens.getAccessToken();
|
||||
//print(t);
|
||||
//print("here1");
|
||||
var request = http2.MultipartRequest(
|
||||
'POST', Uri.parse("${AppEnviroment.baseApiUrl}/minio/upload/file/"));
|
||||
request.headers['accept'] = 'application/json';
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['Content-Type'] = 'multipart/form-data';
|
||||
request.fields['app_id'] = widget.selectedPatient.app_id;
|
||||
request.fields['folder'] = "patient_files";
|
||||
request.files.add(await http2.MultipartFile.fromBytes('file', file.bytes!,
|
||||
filename: file.name.replaceAll(RegExp(r' '), '-')));
|
||||
//print("here2");
|
||||
var response1 = await request.send();
|
||||
//print("here3");
|
||||
//print(response1.statusCode);
|
||||
//print(response1.toString());
|
||||
if (response1.statusCode == 200) {
|
||||
//print("here3");
|
||||
var fname = file.name.replaceAll(RegExp(r' '), '-');
|
||||
var filePath = "${widget.selectedPatient.app_id}/patient_files/$fname";
|
||||
var response2 = await http.post(
|
||||
Uri.parse("${AppEnviroment.baseApiUrl}/files/insert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"file_path": filePath,
|
||||
"file_name": fname,
|
||||
"app_id": widget.selectedPatient.app_id
|
||||
}),
|
||||
);
|
||||
//print("here5");
|
||||
//print(response2.statusCode);
|
||||
if (response2.statusCode == 201) {
|
||||
setState(() {
|
||||
selectedFileController.clear();
|
||||
futueFiles = fetchFiles();
|
||||
});
|
||||
// end loading circle
|
||||
Navigator.of(context).pop();
|
||||
String message =
|
||||
"The file ${file.name.replaceAll(RegExp(r' '), '-')} has been successfully generated and added to ${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}'s record. You can now access and download it for their use.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<PFile>> fetchFiles() async {
|
||||
final response = await http.get(Uri.parse(
|
||||
"${AppEnviroment.baseApiUrl}/files/patients/${widget.selectedPatient.app_id}"));
|
||||
|
||||
//print(response.statusCode);
|
||||
//print(response.body);
|
||||
if (response.statusCode == 200) {
|
||||
Iterable l = jsonDecode(response.body);
|
||||
List<PFile> files =
|
||||
List<PFile>.from(l.map((model) => PFile.fromJson(model)));
|
||||
return files;
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
throw Exception('failed to load patients');
|
||||
}
|
||||
}
|
||||
|
||||
void successPopUp(String message) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return MIHSuccessMessage(
|
||||
successType: "Success",
|
||||
successMessage: message,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void messagePopUp(error) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(error),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void medCertPopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Create Medical Certificate",
|
||||
windowTools: const [],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
windowBody: [
|
||||
Medcertinput(
|
||||
startDateController: startDateController,
|
||||
endDateTextController: endDateTextController,
|
||||
retDateTextController: retDateTextController,
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
buttonText: "Generate",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
onTap: () async {
|
||||
if (isMedCertFieldsFilled()) {
|
||||
await generateMedCert();
|
||||
//Navigator.pop(context);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void prescritionPopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Create Prescription",
|
||||
windowTools: const [],
|
||||
onWindowTapClose: () {
|
||||
medicineController.clear();
|
||||
quantityController.clear();
|
||||
dosageController.clear();
|
||||
timesDailyController.clear();
|
||||
noDaysController.clear();
|
||||
noRepeatsController.clear();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
windowBody: [
|
||||
PrescripInput(
|
||||
medicineController: medicineController,
|
||||
quantityController: quantityController,
|
||||
dosageController: dosageController,
|
||||
timesDailyController: timesDailyController,
|
||||
noDaysController: noDaysController,
|
||||
noRepeatsController: noRepeatsController,
|
||||
outputController: outputController,
|
||||
selectedPatient: widget.selectedPatient,
|
||||
signedInUser: widget.signedInUser,
|
||||
business: widget.business,
|
||||
businessUser: widget.businessUser,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void uploudFilePopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Upload File",
|
||||
windowTools: const [],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
windowBody: [
|
||||
MIHFileField(
|
||||
controller: selectedFileController,
|
||||
hintText: "Select File",
|
||||
editable: false,
|
||||
required: true,
|
||||
onPressed: () async {
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png', 'pdf'],
|
||||
);
|
||||
if (result == null) return;
|
||||
final selectedFile = result.files.first;
|
||||
setState(() {
|
||||
selected = selectedFile;
|
||||
});
|
||||
|
||||
setState(() {
|
||||
selectedFileController.text = selectedFile.name;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
buttonText: "Add File",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
onTap: () {
|
||||
if (isFileFieldsFilled()) {
|
||||
uploadSelectedFile(selected);
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void internetConnectionPopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Internet Connection");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool isMedCertFieldsFilled() {
|
||||
if (startDateController.text.isEmpty ||
|
||||
endDateTextController.text.isEmpty ||
|
||||
retDateTextController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool isFileFieldsFilled() {
|
||||
if (selectedFileController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> setIcons() {
|
||||
if (widget.type == "personal") {
|
||||
return [
|
||||
Text(
|
||||
"Documents",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
uploudFilePopUp();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.add,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
)
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
Text(
|
||||
"Documents",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
medCertPopUp();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.sick_outlined,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
prescritionPopUp();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.medication_outlined,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
uploudFilePopUp();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.add,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
startDateController.dispose();
|
||||
endDateTextController.dispose();
|
||||
retDateTextController.dispose();
|
||||
selectedFileController.dispose();
|
||||
medicineController.dispose();
|
||||
quantityController.dispose();
|
||||
dosageController.dispose();
|
||||
timesDailyController.dispose();
|
||||
noDaysController.dispose();
|
||||
noRepeatsController.dispose();
|
||||
outputController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
futueFiles = fetchFiles();
|
||||
//patientDetails = getPatientDetails() as Patient;
|
||||
//getUserDetails();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: futueFiles,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(
|
||||
child: Mihloadingcircle(),
|
||||
);
|
||||
} else if (snapshot.hasData) {
|
||||
final filesList = snapshot.data!;
|
||||
return Column(children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: setIcons(),
|
||||
),
|
||||
Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
const SizedBox(height: 10),
|
||||
BuildFilesList(
|
||||
files: filesList,
|
||||
signedInUser: widget.signedInUser,
|
||||
selectedPatient: widget.selectedPatient,
|
||||
business: widget.business,
|
||||
businessUser: widget.businessUser,
|
||||
type: widget.type,
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
return const Center(
|
||||
child: Text("Error Loading Notes"),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
679
Frontend/lib/mih_packages/patient_profile/patient_manager.dart
Normal file
679
Frontend/lib/mih_packages/patient_profile/patient_manager.dart
Normal file
@@ -0,0 +1,679 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter_swipe_detector/flutter_swipe_detector.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
import '../../mih_apis/mih_api_calls.dart';
|
||||
import '../../mih_components/mih_calendar.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_search_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
import '../../mih_objects/patient_access.dart';
|
||||
import '../../mih_objects/patient_queue.dart';
|
||||
import '../../mih_objects/patients.dart';
|
||||
import 'builder/build_patient_access_list.dart';
|
||||
import 'builder/build_patient_list.dart';
|
||||
import 'builder/build_patient_queue_list.dart';
|
||||
|
||||
class PatientManager extends StatefulWidget {
|
||||
//final AppUser signedInUser;
|
||||
final BusinessArguments arguments;
|
||||
const PatientManager({
|
||||
super.key,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PatientManager> createState() => _PatientManagerState();
|
||||
}
|
||||
|
||||
//
|
||||
class _PatientManagerState extends State<PatientManager> {
|
||||
TextEditingController searchController = TextEditingController();
|
||||
TextEditingController accessSearchController = TextEditingController();
|
||||
TextEditingController queueDateController = TextEditingController();
|
||||
|
||||
String baseUrl = AppEnviroment.baseApiUrl;
|
||||
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
String searchString = "";
|
||||
String accessSearchString = "";
|
||||
var now = DateTime.now();
|
||||
var formatter = DateFormat('yyyy-MM-dd');
|
||||
late String formattedDate;
|
||||
bool start = true;
|
||||
int _selectedIndex = 0;
|
||||
|
||||
late Future<List<Patient>> patientSearchResults;
|
||||
late Future<List<PatientAccess>> patientAccessResults;
|
||||
late Future<List<PatientQueue>> patientQueueResults;
|
||||
|
||||
//Waiting Room Widgets/ Functions
|
||||
List<PatientQueue> filterQueueResults(
|
||||
List<PatientQueue> queueList, String query) {
|
||||
List<PatientQueue> templist = [];
|
||||
//print(query);
|
||||
for (var item in queueList) {
|
||||
if (item.date_time.contains(query)) {
|
||||
//print(item.medical_aid_no);
|
||||
templist.add(item);
|
||||
}
|
||||
}
|
||||
//print(templist);
|
||||
return templist;
|
||||
}
|
||||
|
||||
Widget displayQueueList(List<PatientQueue> patientQueueList) {
|
||||
if (patientQueueList.isNotEmpty) {
|
||||
return BuildPatientQueueList(
|
||||
patientQueue: patientQueueList,
|
||||
signedInUser: widget.arguments.signedInUser,
|
||||
business: widget.arguments.business,
|
||||
businessUser: widget.arguments.businessUser,
|
||||
);
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 35.0),
|
||||
child: Center(
|
||||
child: Text(
|
||||
"No Appointments for $formattedDate",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!.theme.messageTextColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget patientQueue() {
|
||||
return Column(mainAxisSize: MainAxisSize.max, children: [
|
||||
//const SizedBox(height: 15),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
"Waiting Room",
|
||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||
),
|
||||
IconButton(
|
||||
iconSize: 20,
|
||||
icon: const Icon(
|
||||
Icons.refresh,
|
||||
),
|
||||
onPressed: () {
|
||||
refreshQueue();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
MIHCalendar(
|
||||
calendarWidth: 500,
|
||||
rowHeight: 35,
|
||||
setDate: (value) {
|
||||
setState(() {
|
||||
queueDateController.text = value;
|
||||
});
|
||||
}),
|
||||
//spacer
|
||||
FutureBuilder(
|
||||
future: patientQueueResults,
|
||||
builder: (context, snapshot) {
|
||||
//print("patient Queue List ${snapshot.hasData}");
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Mihloadingcircle();
|
||||
} else if (snapshot.connectionState == ConnectionState.done) {
|
||||
List<PatientQueue> patientQueueList;
|
||||
// if (searchString == "") {
|
||||
// patientQueueList = [];
|
||||
// } else {
|
||||
patientQueueList = filterQueueResults(
|
||||
snapshot.requireData, queueDateController.text);
|
||||
// print(patientQueueList);
|
||||
// }
|
||||
|
||||
return displayQueueList(patientQueueList);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"Error pulling Patients Data\n$baseUrl/patients/search/$searchString",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!.theme.errorColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
void refreshQueue() {
|
||||
setState(() {
|
||||
start = true;
|
||||
});
|
||||
checkforchange();
|
||||
}
|
||||
|
||||
void checkforchange() {
|
||||
if (start == true) {
|
||||
setState(() {
|
||||
patientQueueResults = MIHApiCalls.fetchBusinessAppointmentsAPICall(
|
||||
queueDateController.text, widget.arguments.business!.business_id);
|
||||
start = false;
|
||||
});
|
||||
}
|
||||
if (formattedDate != queueDateController.text) {
|
||||
setState(() {
|
||||
patientQueueResults = MIHApiCalls.fetchBusinessAppointmentsAPICall(
|
||||
queueDateController.text, widget.arguments.business!.business_id);
|
||||
formattedDate = queueDateController.text;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//Patient Lookup Widgets/ Functions
|
||||
|
||||
List<Patient> filterSearchResults(List<Patient> patList, String query) {
|
||||
List<Patient> templist = [];
|
||||
//print(query);
|
||||
for (var item in patList) {
|
||||
if (item.id_no.contains(searchString) ||
|
||||
item.medical_aid_no.contains(searchString)) {
|
||||
//print(item.medical_aid_no);
|
||||
templist.add(item);
|
||||
}
|
||||
}
|
||||
return templist;
|
||||
}
|
||||
|
||||
Widget displayPatientList(List<Patient> patientsList, String searchString) {
|
||||
if (patientsList.isNotEmpty) {
|
||||
return BuildPatientsList(
|
||||
patients: patientsList,
|
||||
signedInUser: widget.arguments.signedInUser,
|
||||
business: widget.arguments.business,
|
||||
arguments: widget.arguments,
|
||||
);
|
||||
} 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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget patientSearch() {
|
||||
return KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
submitPatientForm();
|
||||
}
|
||||
},
|
||||
child: Column(mainAxisSize: MainAxisSize.max, children: [
|
||||
const Text(
|
||||
"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: searchController,
|
||||
hintText: "ID or Medical Aid No. Search",
|
||||
required: false,
|
||||
editable: true,
|
||||
onTap: () {
|
||||
submitPatientForm();
|
||||
},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
searchController.clear();
|
||||
searchString = "";
|
||||
});
|
||||
submitPatientForm();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.filter_alt_off,
|
||||
size: 25,
|
||||
))
|
||||
],
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder(
|
||||
future: patientSearchResults,
|
||||
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 (searchString == "") {
|
||||
patientsList = [];
|
||||
} else {
|
||||
patientsList =
|
||||
filterSearchResults(snapshot.data!, searchString);
|
||||
//print(patientsList);
|
||||
}
|
||||
|
||||
return displayPatientList(patientsList, searchString);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"Error pulling Patients Data\n$baseUrl/patients/search/$searchString",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void submitPatientForm() {
|
||||
if (searchController.text != "") {
|
||||
setState(() {
|
||||
searchString = searchController.text;
|
||||
patientSearchResults = MIHApiCalls.fetchPatients(searchString);
|
||||
});
|
||||
}
|
||||
// else {
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return const MIHErrorMessage(errorType: "Input Error");
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
Widget displayPatientAccessList(List<PatientAccess> patientsAccessList) {
|
||||
if (patientsAccessList.isNotEmpty) {
|
||||
return BuildPatientAccessList(
|
||||
patientAccesses: patientsAccessList,
|
||||
signedInUser: widget.arguments.signedInUser,
|
||||
business: widget.arguments.business,
|
||||
arguments: widget.arguments,
|
||||
);
|
||||
}
|
||||
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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget patientAccessSearch() {
|
||||
return KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
submitPatientAccessForm();
|
||||
}
|
||||
},
|
||||
child: Column(mainAxisSize: MainAxisSize.max, children: [
|
||||
const Text(
|
||||
"My Patient List",
|
||||
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: accessSearchController,
|
||||
hintText: "ID Search",
|
||||
required: false,
|
||||
editable: true,
|
||||
onTap: () {
|
||||
submitPatientAccessForm();
|
||||
},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
accessSearchController.clear();
|
||||
accessSearchString = "";
|
||||
});
|
||||
submitPatientAccessForm();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.filter_alt_off,
|
||||
size: 25,
|
||||
))
|
||||
],
|
||||
),
|
||||
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder(
|
||||
future: patientAccessResults,
|
||||
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 (accessSearchString == "") {
|
||||
patientsAccessList = snapshot.data!;
|
||||
} else {
|
||||
patientsAccessList =
|
||||
filterAccessResults(snapshot.data!, accessSearchString);
|
||||
//print(patientsList);
|
||||
}
|
||||
|
||||
return displayPatientAccessList(patientsAccessList);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
"Error pulling Patient Access Data\n$baseUrl/access-requests/business/patient/${widget.arguments.business!.business_id}",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.errorColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void submitPatientAccessForm() {
|
||||
// if (searchController.text != "") {
|
||||
setState(() {
|
||||
accessSearchString = accessSearchController.text;
|
||||
patientAccessResults = MIHApiCalls.getPatientAccessListOfBusiness(
|
||||
widget.arguments.business!.business_id);
|
||||
});
|
||||
// } else {
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return const MIHErrorMessage(errorType: "Input Error");
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
//Layout Widgets/ Functions
|
||||
|
||||
Widget showSelection(int index) {
|
||||
if (index == 0) {
|
||||
return SizedBox(
|
||||
//width: 660,
|
||||
child: patientQueue(),
|
||||
);
|
||||
} else if (index == 1) {
|
||||
return SizedBox(
|
||||
//width: 660,
|
||||
child: patientAccessSearch(),
|
||||
);
|
||||
} else {
|
||||
return SizedBox(
|
||||
//width: 660,
|
||||
child: patientSearch(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
Navigator.of(context).popAndPushNamed(
|
||||
'/',
|
||||
arguments: false,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.end,
|
||||
headerItems: [
|
||||
//============ Waiting Room ================
|
||||
Visibility(
|
||||
visible: _selectedIndex != 0,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 0;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.people,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: _selectedIndex == 0,
|
||||
child: IconButton.filled(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 0;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.people,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
//============ My Patient List ================
|
||||
Visibility(
|
||||
visible: _selectedIndex != 1,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 1;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.check_box_outlined,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: _selectedIndex == 1,
|
||||
child: IconButton.filled(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 1;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.check_box_outlined,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
//============ Patient Lookup ================
|
||||
Visibility(
|
||||
visible: _selectedIndex != 2,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 2;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.search,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: _selectedIndex == 2,
|
||||
child: IconButton.filled(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 2;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.search,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: true,
|
||||
bodyItems: [
|
||||
showSelection(_selectedIndex),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
searchController.dispose();
|
||||
accessSearchController.dispose();
|
||||
queueDateController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
patientSearchResults = MIHApiCalls.fetchPatients("abc");
|
||||
patientAccessResults = MIHApiCalls.getPatientAccessListOfBusiness(
|
||||
widget.arguments.business!.business_id);
|
||||
queueDateController.addListener(checkforchange);
|
||||
setState(() {
|
||||
formattedDate = formatter.format(now);
|
||||
queueDateController.text = formattedDate;
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SwipeDetector(
|
||||
onSwipeLeft: (offset) {
|
||||
if (_selectedIndex < 2) {
|
||||
setState(() {
|
||||
_selectedIndex += 1;
|
||||
});
|
||||
}
|
||||
//print("swipe left");
|
||||
},
|
||||
onSwipeRight: (offset) {
|
||||
if (_selectedIndex > 0) {
|
||||
setState(() {
|
||||
_selectedIndex -= 1;
|
||||
});
|
||||
}
|
||||
//print("swipe right");
|
||||
},
|
||||
child: MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
455
Frontend/lib/mih_packages/patient_profile/patient_notes.dart
Normal file
455
Frontend/lib/mih_packages/patient_profile/patient_notes.dart
Normal file
@@ -0,0 +1,455 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_multiline_text_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_text_input.dart';
|
||||
import '../../mih_components/mih_layout/mih_window.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/business.dart';
|
||||
import '../../mih_objects/business_user.dart';
|
||||
import '../../mih_objects/notes.dart';
|
||||
import '../../mih_objects/patients.dart';
|
||||
import 'builder/build_notes_list.dart';
|
||||
|
||||
class PatientNotes extends StatefulWidget {
|
||||
final String patientAppId;
|
||||
final Patient selectedPatient;
|
||||
final AppUser signedInUser;
|
||||
final Business? business;
|
||||
final BusinessUser? businessUser;
|
||||
final String type;
|
||||
const PatientNotes({
|
||||
super.key,
|
||||
required this.patientAppId,
|
||||
required this.selectedPatient,
|
||||
required this.signedInUser,
|
||||
required this.business,
|
||||
required this.businessUser,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PatientNotes> createState() => _PatientNotesState();
|
||||
}
|
||||
|
||||
class _PatientNotesState extends State<PatientNotes> {
|
||||
String endpoint = "${AppEnviroment.baseApiUrl}/notes/patients/";
|
||||
String apiUrlAddNote = "${AppEnviroment.baseApiUrl}/notes/insert/";
|
||||
final titleController = TextEditingController();
|
||||
final noteTextController = TextEditingController();
|
||||
final officeController = TextEditingController();
|
||||
final dateController = TextEditingController();
|
||||
final doctorController = TextEditingController();
|
||||
late Future<List<Note>> futueNotes;
|
||||
|
||||
Future<List<Note>> fetchNotes(String endpoint) async {
|
||||
final response = await http.get(Uri.parse(
|
||||
"${AppEnviroment.baseApiUrl}/notes/patients/${widget.selectedPatient.app_id}"));
|
||||
if (response.statusCode == 200) {
|
||||
Iterable l = jsonDecode(response.body);
|
||||
List<Note> notes =
|
||||
List<Note>.from(l.map((model) => Note.fromJson(model)));
|
||||
//print("Here notes");
|
||||
return notes;
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
throw Exception('failed to load patients');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addPatientNoteAPICall() async {
|
||||
// String title = "";
|
||||
// if (widget.businessUser!.title == "Doctor") {
|
||||
// title = "Dr.";
|
||||
// }
|
||||
var response = await http.post(
|
||||
Uri.parse("${AppEnviroment.baseApiUrl}/notes/insert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"note_name": titleController.text,
|
||||
"note_text": noteTextController.text,
|
||||
"doc_office": officeController.text,
|
||||
"doctor": doctorController.text,
|
||||
"app_id": widget.selectedPatient.app_id,
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 201) {
|
||||
setState(() {
|
||||
futueNotes = fetchNotes(endpoint + widget.patientAppId.toString());
|
||||
});
|
||||
// Navigator.of(context)
|
||||
// .pushNamed('/patient-manager', arguments: widget.userEmail);
|
||||
String message =
|
||||
"Your note has been successfully added to the patients medical record. You can now view it alongside their other important information.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
}
|
||||
|
||||
void successPopUp(String message) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return MIHSuccessMessage(
|
||||
successType: "Success",
|
||||
successMessage: message,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void internetConnectionPopUp() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Internet Connection");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void messagePopUp(error) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(error),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void addNotePopUp() {
|
||||
DateTime now = new DateTime.now();
|
||||
DateTime date = new DateTime(now.year, now.month, now.day);
|
||||
var title = "";
|
||||
if (widget.businessUser!.title == "Doctor") {
|
||||
title = "Dr.";
|
||||
}
|
||||
setState(() {
|
||||
officeController.text = widget.business!.Name;
|
||||
doctorController.text =
|
||||
"$title ${widget.signedInUser.fname} ${widget.signedInUser.lname}";
|
||||
dateController.text = date.toString().substring(0, 10);
|
||||
});
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => MIHWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "Add Note",
|
||||
windowTools: const [],
|
||||
onWindowTapClose: () {
|
||||
Navigator.pop(context);
|
||||
titleController.clear();
|
||||
noteTextController.clear();
|
||||
},
|
||||
windowBody: [
|
||||
MIHTextField(
|
||||
controller: officeController,
|
||||
hintText: "Office",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: doctorController,
|
||||
hintText: "Created By",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: dateController,
|
||||
hintText: "Created Date",
|
||||
editable: false,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHTextField(
|
||||
controller: titleController,
|
||||
hintText: "Note Title",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
SizedBox(
|
||||
//width: 700,
|
||||
height: 250,
|
||||
child: MIHMLTextField(
|
||||
controller: noteTextController,
|
||||
hintText: "Note Details",
|
||||
editable: true,
|
||||
required: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () {
|
||||
if (isFieldsFilled()) {
|
||||
addPatientNoteAPICall();
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
buttonText: "Add Note",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => Dialog(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// Container(
|
||||
// padding: const EdgeInsets.all(10.0),
|
||||
// width: 700.0,
|
||||
// //height: 500.0,
|
||||
// decoration: BoxDecoration(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
// borderRadius: BorderRadius.circular(25.0),
|
||||
// border: Border.all(
|
||||
// color:
|
||||
// MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
// width: 5.0),
|
||||
// ),
|
||||
// child: SingleChildScrollView(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Add Note",
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// color: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// fontSize: 35.0,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 25.0),
|
||||
// SizedBox(
|
||||
// width: 700,
|
||||
// child: MIHTextField(
|
||||
// controller: officeController,
|
||||
// hintText: "Office",
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// SizedBox(
|
||||
// width: 700,
|
||||
// child: MIHTextField(
|
||||
// controller: doctorController,
|
||||
// hintText: "Created By",
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// SizedBox(
|
||||
// width: 700,
|
||||
// child: MIHTextField(
|
||||
// controller: dateController,
|
||||
// hintText: "Created Date",
|
||||
// editable: false,
|
||||
// required: true,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// SizedBox(
|
||||
// width: 700,
|
||||
// child: MIHTextField(
|
||||
// controller: titleController,
|
||||
// hintText: "Note Title",
|
||||
// editable: true,
|
||||
// required: true,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
// SizedBox(
|
||||
// width: 700,
|
||||
// height: 250,
|
||||
// child: MIHMLTextField(
|
||||
// controller: noteTextController,
|
||||
// hintText: "Note Details",
|
||||
// editable: true,
|
||||
// required: true,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 30.0),
|
||||
// SizedBox(
|
||||
// width: 300,
|
||||
// height: 50,
|
||||
// child: MIHButton(
|
||||
// onTap: () {
|
||||
// if (isFieldsFilled()) {
|
||||
// addPatientNoteAPICall();
|
||||
// Navigator.pop(context);
|
||||
// } else {
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return const MIHErrorMessage(
|
||||
// errorType: "Input Error");
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
// },
|
||||
// buttonText: "Add Note",
|
||||
// buttonColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .secondaryColor(),
|
||||
// textColor: MzanziInnovationHub.of(context)!
|
||||
// .theme
|
||||
// .primaryColor(),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 5,
|
||||
// right: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pop(context);
|
||||
// titleController.clear();
|
||||
// noteTextController.clear();
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.close,
|
||||
// color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
|
||||
bool isFieldsFilled() {
|
||||
if (titleController.text.isEmpty || noteTextController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> setIcons() {
|
||||
if (widget.type == "personal") {
|
||||
return [
|
||||
Text(
|
||||
"Notes",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
),
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
Text(
|
||||
"Notes",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
addNotePopUp();
|
||||
},
|
||||
icon: Icon(Icons.add,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
titleController.dispose();
|
||||
noteTextController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
futueNotes = fetchNotes(endpoint + widget.patientAppId);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: futueNotes,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(
|
||||
child: Mihloadingcircle(),
|
||||
);
|
||||
} else if (snapshot.hasData) {
|
||||
final notesList = snapshot.data!;
|
||||
return Column(children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: setIcons(),
|
||||
),
|
||||
Divider(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
|
||||
const SizedBox(height: 10),
|
||||
BuildNotesList(
|
||||
notes: notesList,
|
||||
signedInUser: widget.signedInUser,
|
||||
selectedPatient: widget.selectedPatient,
|
||||
business: widget.business,
|
||||
businessUser: widget.businessUser,
|
||||
type: widget.type,
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
return const Center(
|
||||
child: Text("Error Loading Notes"),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
355
Frontend/lib/mih_packages/patient_profile/patient_view.dart
Normal file
355
Frontend/lib/mih_packages/patient_profile/patient_view.dart
Normal file
@@ -0,0 +1,355 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_swipe_detector/flutter_swipe_detector.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
import '../../mih_objects/patients.dart';
|
||||
import 'patient_details.dart';
|
||||
import 'patient_files.dart';
|
||||
import 'patient_notes.dart';
|
||||
|
||||
class PatientView extends StatefulWidget {
|
||||
//final AppUser signedInUser;
|
||||
final PatientViewArguments arguments;
|
||||
const PatientView({
|
||||
super.key,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PatientView> createState() => _PatientViewState();
|
||||
}
|
||||
|
||||
class _PatientViewState extends State<PatientView> {
|
||||
int _selectedIndex = 0;
|
||||
late double popUpWidth;
|
||||
late double? popUpheight;
|
||||
late double popUpTitleSize;
|
||||
late double popUpSubtitleSize;
|
||||
late double popUpBodySize;
|
||||
late double popUpIconSize;
|
||||
late double popUpPaddingSize;
|
||||
late double width;
|
||||
late double height;
|
||||
|
||||
Future<Patient?> fetchPatient() async {
|
||||
//print("Patien manager page: $endpoint");
|
||||
var patientAppId = widget.arguments.selectedPatient!.app_id;
|
||||
|
||||
final response = await http
|
||||
.get(Uri.parse("${AppEnviroment.baseApiUrl}/patients/$patientAppId"));
|
||||
// print("Here");
|
||||
// print("Body: ${response.body}");
|
||||
// print("Code: ${response.statusCode}");
|
||||
// var errorCode = response.statusCode.toString();
|
||||
// var errorBody = response.body;
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
//print("Here1");
|
||||
var decodedData = jsonDecode(response.body);
|
||||
// print("Here2");
|
||||
Patient patients = Patient.fromJson(decodedData as Map<String, dynamic>);
|
||||
// print("Here3");
|
||||
// print(patients);
|
||||
return patients;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void checkScreenSize() {
|
||||
if (MzanziInnovationHub.of(context)!.theme.screenType == "desktop") {
|
||||
setState(() {
|
||||
popUpWidth = (width / 4) * 2;
|
||||
popUpheight = null;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
popUpWidth = width - (width * 0.1);
|
||||
popUpheight = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget showSelection(int index) {
|
||||
if (index == 0) {
|
||||
return PatientDetails(
|
||||
signedInUser: widget.arguments.signedInUser,
|
||||
selectedPatient: widget.arguments.selectedPatient!,
|
||||
type: widget.arguments.type,
|
||||
);
|
||||
} else if (index == 1) {
|
||||
return PatientNotes(
|
||||
patientAppId: widget.arguments.selectedPatient!.app_id,
|
||||
selectedPatient: widget.arguments.selectedPatient!,
|
||||
signedInUser: widget.arguments.signedInUser,
|
||||
business: widget.arguments.business,
|
||||
businessUser: widget.arguments.businessUser,
|
||||
type: widget.arguments.type,
|
||||
);
|
||||
} else {
|
||||
return PatientFiles(
|
||||
patientIndex: widget.arguments.selectedPatient!.idpatients,
|
||||
selectedPatient: widget.arguments.selectedPatient!,
|
||||
signedInUser: widget.arguments.signedInUser,
|
||||
business: widget.arguments.business,
|
||||
businessUser: widget.arguments.businessUser,
|
||||
type: widget.arguments.type,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
if (widget.arguments.type == "Personal") {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).popAndPushNamed(
|
||||
'/',
|
||||
arguments: true,
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.end,
|
||||
headerItems: [
|
||||
//============ Patient Details ================
|
||||
Visibility(
|
||||
visible: _selectedIndex != 0,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 0;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.perm_identity,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: _selectedIndex == 0,
|
||||
child: IconButton.filled(
|
||||
iconSize: 35,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 0;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.perm_identity,
|
||||
),
|
||||
),
|
||||
),
|
||||
//============ Patient Notes ================
|
||||
Visibility(
|
||||
visible: _selectedIndex != 1,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 1;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.article_outlined,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: _selectedIndex == 1,
|
||||
child: IconButton.filled(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 1;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.article_outlined,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
//============ Patient Files ================
|
||||
Visibility(
|
||||
visible: _selectedIndex != 2,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 2;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.file_present,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: _selectedIndex == 2,
|
||||
child: IconButton.filled(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 2;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.file_present,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
return MIHBody(
|
||||
borderOn: true,
|
||||
bodyItems: [showSelection(_selectedIndex)],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var size = MediaQuery.of(context).size;
|
||||
setState(() {
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
});
|
||||
checkScreenSize();
|
||||
return SwipeDetector(
|
||||
onSwipeLeft: (offset) {
|
||||
if (_selectedIndex < 2) {
|
||||
setState(() {
|
||||
_selectedIndex += 1;
|
||||
});
|
||||
}
|
||||
//print("swipe left");
|
||||
},
|
||||
onSwipeRight: (offset) {
|
||||
if (_selectedIndex > 0) {
|
||||
setState(() {
|
||||
_selectedIndex -= 1;
|
||||
});
|
||||
}
|
||||
//print("swipe right");
|
||||
},
|
||||
child: MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
secondaryActionButton: null,
|
||||
body: getBody(),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
),
|
||||
);
|
||||
// return Scaffold(
|
||||
// body: SafeArea(
|
||||
// child: SingleChildScrollView(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// Container(
|
||||
// width: width,
|
||||
// height: height,
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// vertical: 10.0, horizontal: 15.0),
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.max,
|
||||
// children: [
|
||||
// Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.end,
|
||||
// mainAxisAlignment: MainAxisAlignment.end,
|
||||
// children: [
|
||||
// IconButton(
|
||||
// onPressed: () {
|
||||
// setState(() {
|
||||
// _selectedIndex = 0;
|
||||
// });
|
||||
// },
|
||||
// icon: const Icon(
|
||||
// Icons.perm_identity,
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// IconButton(
|
||||
// onPressed: () {
|
||||
// setState(() {
|
||||
// _selectedIndex = 1;
|
||||
// });
|
||||
// },
|
||||
// icon: const Icon(
|
||||
// Icons.article_outlined,
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// IconButton(
|
||||
// onPressed: () {
|
||||
// setState(() {
|
||||
// _selectedIndex = 2;
|
||||
// });
|
||||
// },
|
||||
// icon: const Icon(
|
||||
// Icons.file_present,
|
||||
// size: 35,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// height: 10.0,
|
||||
// ),
|
||||
// showSelection(_selectedIndex),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 10,
|
||||
// left: 5,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
// child: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// icon: const Icon(Icons.arrow_back),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
}
|
||||
570
Frontend/lib/mih_packages/patient_profile/prescip_input.dart
Normal file
570
Frontend/lib/mih_packages/patient_profile/prescip_input.dart
Normal file
@@ -0,0 +1,570 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../main.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
import '../../mih_components/medicine_search.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_button.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
|
||||
import '../../mih_components/mih_inputs_and_buttons/mih_search_input.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
|
||||
import '../../mih_env/env.dart';
|
||||
import '../../mih_objects/app_user.dart';
|
||||
import '../../mih_objects/arguments.dart';
|
||||
import '../../mih_objects/business.dart';
|
||||
import '../../mih_objects/business_user.dart';
|
||||
import '../../mih_objects/patients.dart';
|
||||
import '../../mih_objects/perscription.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;
|
||||
final Patient selectedPatient;
|
||||
final AppUser signedInUser;
|
||||
final Business? business;
|
||||
final BusinessUser? businessUser;
|
||||
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,
|
||||
required this.selectedPatient,
|
||||
required this.signedInUser,
|
||||
required this.business,
|
||||
required this.businessUser,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PrescripInput> createState() => _PrescripInputState();
|
||||
}
|
||||
|
||||
class _PrescripInputState extends State<PrescripInput> {
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
List<Perscription> perscriptionObjOutput = [];
|
||||
late double width;
|
||||
late double height;
|
||||
|
||||
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"
|
||||
];
|
||||
|
||||
Future<void> generatePerscription() async {
|
||||
//start loading circle
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
|
||||
var response1 = await http.post(
|
||||
Uri.parse("${AppEnviroment.baseApiUrl}/minio/generate/perscription/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"app_id": widget.selectedPatient.app_id,
|
||||
"fullName":
|
||||
"${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}",
|
||||
"id_no": widget.selectedPatient.id_no,
|
||||
"docfname":
|
||||
"DR. ${widget.signedInUser.fname} ${widget.signedInUser.lname}",
|
||||
"busName": widget.business!.Name,
|
||||
"busAddr": "*TO BE ADDED IN THE FUTURE*",
|
||||
"busNo": widget.business!.contact_no,
|
||||
"busEmail": widget.business!.bus_email,
|
||||
"logo_path": widget.business!.logo_path,
|
||||
"sig_path": widget.businessUser!.sig_path,
|
||||
"data": perscriptionObjOutput,
|
||||
}),
|
||||
);
|
||||
//print(response1.statusCode);
|
||||
DateTime now = new DateTime.now();
|
||||
DateTime date = new DateTime(now.year, now.month, now.day);
|
||||
String fileName =
|
||||
"Perscription-${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}-${date.toString().substring(0, 10)}.pdf";
|
||||
if (response1.statusCode == 200) {
|
||||
var response2 = await http.post(
|
||||
Uri.parse("${AppEnviroment.baseApiUrl}/files/insert/"),
|
||||
headers: <String, String>{
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: jsonEncode(<String, dynamic>{
|
||||
"file_path":
|
||||
"${widget.selectedPatient.app_id}/patient_files/$fileName",
|
||||
"file_name": fileName,
|
||||
"app_id": widget.selectedPatient.app_id
|
||||
}),
|
||||
);
|
||||
//print(response2.statusCode);
|
||||
if (response2.statusCode == 201) {
|
||||
setState(() {
|
||||
//To do
|
||||
widget.medicineController.clear();
|
||||
widget.dosageController.clear();
|
||||
widget.timesDailyController.clear();
|
||||
widget.noDaysController.clear();
|
||||
widget.timesDailyController.clear();
|
||||
widget.noRepeatsController.clear();
|
||||
widget.quantityController.clear();
|
||||
widget.outputController.clear();
|
||||
// futueFiles = fetchFiles();
|
||||
});
|
||||
// end loading circle
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed('/patient-manager/patient',
|
||||
arguments: PatientViewArguments(
|
||||
widget.signedInUser,
|
||||
widget.selectedPatient,
|
||||
widget.businessUser,
|
||||
widget.business,
|
||||
"business",
|
||||
));
|
||||
String message =
|
||||
"The perscription $fileName has been successfully generated and added to ${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}'s record. You can now access and download it for their use.";
|
||||
successPopUp(message);
|
||||
} else {
|
||||
internetConnectionPopUp();
|
||||
}
|
||||
} 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 getMedsPopUp(TextEditingController medSearch) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return MedicineSearch(
|
||||
searchVlaue: medSearch,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool isFieldsFilled() {
|
||||
if (widget.medicineController.text.isEmpty ||
|
||||
// widget.quantityController.text.isEmpty ||
|
||||
widget.dosageController.text.isEmpty ||
|
||||
widget.timesDailyController.text.isEmpty ||
|
||||
widget.noDaysController.text.isEmpty ||
|
||||
widget.noRepeatsController.text.isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void updatePerscriptionList() {
|
||||
String name;
|
||||
String unit;
|
||||
String form;
|
||||
List<String> medNameList = widget.medicineController.text.split("%t");
|
||||
if (medNameList.length == 1) {
|
||||
name = medNameList[0];
|
||||
unit = "";
|
||||
form = "";
|
||||
} else {
|
||||
name = medNameList[0];
|
||||
unit = medNameList[1];
|
||||
form = medNameList[2];
|
||||
}
|
||||
int quantityCalc = calcQuantity(
|
||||
widget.dosageController.text,
|
||||
widget.timesDailyController.text,
|
||||
widget.noDaysController.text,
|
||||
medNameList[2].toLowerCase());
|
||||
Perscription tempObj = Perscription(
|
||||
name: name,
|
||||
unit: unit,
|
||||
form: form,
|
||||
fullForm: getFullDoagesForm(form),
|
||||
quantity: "$quantityCalc",
|
||||
dosage: widget.dosageController.text,
|
||||
times: widget.timesDailyController.text,
|
||||
days: widget.noDaysController.text,
|
||||
repeats: widget.noRepeatsController.text,
|
||||
);
|
||||
perscriptionObjOutput.add(tempObj);
|
||||
}
|
||||
|
||||
String getPerscTitle(int index) {
|
||||
return "${perscriptionObjOutput[index].name} - ${perscriptionObjOutput[index].form}";
|
||||
}
|
||||
|
||||
String getPerscSubtitle(int index) {
|
||||
if (perscriptionObjOutput[index].form.toLowerCase() == "syr") {
|
||||
String unit = perscriptionObjOutput[index].unit.toLowerCase();
|
||||
if (perscriptionObjOutput[index].unit.toLowerCase().contains("ml")) {
|
||||
unit = "ml";
|
||||
}
|
||||
return "${perscriptionObjOutput[index].dosage} $unit, ${perscriptionObjOutput[index].times} time(s) daily, for ${perscriptionObjOutput[index].days} day(s)\nQuantity: ${perscriptionObjOutput[index].quantity}\nNo. of repeats: ${perscriptionObjOutput[index].repeats}";
|
||||
} else {
|
||||
return "${perscriptionObjOutput[index].dosage} ${perscriptionObjOutput[index].fullForm}(s), ${perscriptionObjOutput[index].times} time(s) daily, for ${perscriptionObjOutput[index].days} day(s)\nQuantity: ${perscriptionObjOutput[index].quantity}\nNo. of repeats: ${perscriptionObjOutput[index].repeats}";
|
||||
}
|
||||
}
|
||||
|
||||
String getFullDoagesForm(String abr) {
|
||||
var dosageFormList = {
|
||||
"liq": "liquid",
|
||||
"tab": "tablet",
|
||||
"cap": "capsule",
|
||||
"cps": "capsule",
|
||||
"oin": "ointment",
|
||||
"lit": "lotion",
|
||||
"lot": "lotion",
|
||||
"inj": "injection",
|
||||
"syr": "syrup",
|
||||
"dsp": "effervescent tablet",
|
||||
"eft": "effervescent tablet",
|
||||
"ear": "drops",
|
||||
"drp": "drops",
|
||||
"opd": "drops",
|
||||
"udv": "vial",
|
||||
"sus": "suspension",
|
||||
"susp": "suspension",
|
||||
"cal": "calasthetic",
|
||||
"sol": "solution",
|
||||
"sln": "solution",
|
||||
"neb": "nebuliser",
|
||||
"inh": "inhaler",
|
||||
"spo": "inhaler",
|
||||
"inf": "infusion",
|
||||
"chg": "chewing Gum",
|
||||
"vac": "vacutainer",
|
||||
"vag": "vaginal gel",
|
||||
"jel": "gel",
|
||||
"eyo": "eye ointment",
|
||||
"vat": "vaginal cream",
|
||||
"poi": "injection",
|
||||
"ped": "powder",
|
||||
"pow": "powder",
|
||||
"por": "powder",
|
||||
"sac": "sachet",
|
||||
"sup": "suppository",
|
||||
"cre": "cream",
|
||||
"ptd": "patch",
|
||||
"ect": "tablet",
|
||||
"nas": "spray",
|
||||
};
|
||||
String form;
|
||||
if (dosageFormList[abr.toLowerCase()] == null) {
|
||||
form = abr;
|
||||
} else {
|
||||
form = dosageFormList[abr.toLowerCase()]!;
|
||||
}
|
||||
return form;
|
||||
}
|
||||
|
||||
int calcQuantity(String dosage, String times, String days, String form) {
|
||||
var dosageFormList = [
|
||||
"tab",
|
||||
"cap",
|
||||
"cps",
|
||||
"dsp",
|
||||
"eft",
|
||||
"udv",
|
||||
"chg",
|
||||
"sac",
|
||||
"sup",
|
||||
"ptd",
|
||||
"ect",
|
||||
];
|
||||
if (dosageFormList.contains(form)) {
|
||||
return int.parse(dosage) * int.parse(times) * int.parse(days);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
Widget displayMedInput() {
|
||||
return Column(
|
||||
children: [
|
||||
//const SizedBox(height: 25.0),
|
||||
|
||||
KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
getMedsPopUp(widget.medicineController);
|
||||
}
|
||||
},
|
||||
child: MIHSearchField(
|
||||
controller: widget.medicineController,
|
||||
hintText: "Medicine",
|
||||
required: true,
|
||||
editable: true,
|
||||
onTap: () {
|
||||
getMedsPopUp(widget.medicineController);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
// SizedBox(
|
||||
// width: 300,
|
||||
// child: MIHDropdownField(
|
||||
// controller: widget.quantityController,
|
||||
// hintText: "Quantity",
|
||||
// dropdownOptions: numberOptions,
|
||||
// required: true,
|
||||
// editable: true,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: widget.dosageController,
|
||||
hintText: "Dosage",
|
||||
dropdownOptions: numberOptions,
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: widget.timesDailyController,
|
||||
hintText: "Times Daily",
|
||||
dropdownOptions: numberOptions,
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: widget.noDaysController,
|
||||
hintText: "No. Days",
|
||||
dropdownOptions: numberOptions,
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
MIHDropdownField(
|
||||
controller: widget.noRepeatsController,
|
||||
hintText: "No. Repeats",
|
||||
dropdownOptions: numberOptions,
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
buttonText: "Add",
|
||||
buttonColor:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
onTap: () {
|
||||
if (isFieldsFilled()) {
|
||||
// int quantity;
|
||||
// int.parse(widget.dosageController.text) *
|
||||
// int.parse(widget.timesDailyController.text) *
|
||||
// int.parse(widget.noDaysController.text);
|
||||
setState(() {
|
||||
//widget.quantityController.text = "$quantity";
|
||||
updatePerscriptionList();
|
||||
widget.medicineController.clear();
|
||||
widget.quantityController.clear();
|
||||
widget.dosageController.clear();
|
||||
widget.timesDailyController.clear();
|
||||
widget.noDaysController.clear();
|
||||
widget.noRepeatsController.clear();
|
||||
});
|
||||
|
||||
//addPatientAPICall();
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget displayPerscList() {
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 550,
|
||||
height: 325,
|
||||
decoration: BoxDecoration(
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
border: Border.all(
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
width: 3.0),
|
||||
),
|
||||
child: ListView.separated(
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Divider(),
|
||||
);
|
||||
},
|
||||
itemCount: perscriptionObjOutput.length,
|
||||
itemBuilder: (context, index) {
|
||||
//final patient = widget.patients[index].id_no.contains(widget.searchString);
|
||||
return ListTile(
|
||||
title: Text(
|
||||
getPerscTitle(index),
|
||||
style: TextStyle(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
getPerscSubtitle(index),
|
||||
style: TextStyle(
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
//onTap: () {},
|
||||
trailing: IconButton(
|
||||
icon: Icon(
|
||||
Icons.delete_forever_outlined,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
perscriptionObjOutput.removeAt(index);
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 50,
|
||||
child: MIHButton(
|
||||
onTap: () async {
|
||||
if (perscriptionObjOutput.isNotEmpty) {
|
||||
//print(jsonEncode(perscriptionObjOutput));
|
||||
await generatePerscription();
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
buttonText: "Generate",
|
||||
buttonColor: MzanziInnovationHub.of(context)!.theme.successColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
//futueMeds = getMedList(endpointMeds);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var size = MediaQuery.of(context).size;
|
||||
setState(() {
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
});
|
||||
return Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// mainAxisSize: MainAxisSize.max,
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(width: 500, child: displayMedInput()),
|
||||
displayPerscList(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
82
Frontend/lib/mih_packages/test/test.dart
Normal file
82
Frontend/lib/mih_packages/test/test.dart
Normal file
@@ -0,0 +1,82 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
|
||||
|
||||
import '../../mih_components/mih_layout/mih_action.dart';
|
||||
import '../../mih_components/mih_layout/mih_body.dart';
|
||||
import '../../mih_components/mih_layout/mih_header.dart';
|
||||
import '../../mih_components/mih_layout/mih_layout_builder.dart';
|
||||
|
||||
class MIHTest extends StatefulWidget {
|
||||
const MIHTest({super.key});
|
||||
|
||||
@override
|
||||
State<MIHTest> createState() => _MIHTestState();
|
||||
}
|
||||
|
||||
class _MIHTestState extends State<MIHTest> {
|
||||
late YoutubePlayerController videoController;
|
||||
String videoLink = "https://www.youtube.com/watch?v=P2bM9eosJ_A";
|
||||
@override
|
||||
void initState() {
|
||||
videoController = YoutubePlayerController(
|
||||
initialVideoId: "P2bM9eosJ_A",
|
||||
);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: MIHAction(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||
'/',
|
||||
arguments: true,
|
||||
(route) => false,
|
||||
);
|
||||
},
|
||||
),
|
||||
header: const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"Test",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
secondaryActionButton: null,
|
||||
body: MIHBody(
|
||||
borderOn: false,
|
||||
bodyItems: [
|
||||
YoutubePlayer(
|
||||
controller: videoController,
|
||||
),
|
||||
],
|
||||
),
|
||||
actionDrawer: null,
|
||||
secondaryActionDrawer: null,
|
||||
bottomNavBar: null,
|
||||
pullDownToRefresh: false,
|
||||
onPullDown: () async {},
|
||||
);
|
||||
// return MIHWindow(
|
||||
// fullscreen: false,
|
||||
// windowTitle: "Test",
|
||||
// windowTools: const [],
|
||||
// onWindowTapClose: () {
|
||||
// Navigator.pop(context);
|
||||
// },
|
||||
// windowBody: [
|
||||
// YoutubePlayer(
|
||||
// controller: videoController,
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user