change pages folder to MIH_Packages
This commit is contained in:
@@ -0,0 +1,335 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_Action.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_Body.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_Header.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_LayoutBuilder.dart';
|
||||
import 'package:patient_manager/components/homeTile.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
||||
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: Icons.arrow_back,
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"About",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
MIHBody getBody() {
|
||||
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 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: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Text(
|
||||
vision,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
//fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: Divider(),
|
||||
),
|
||||
Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
children: [
|
||||
founderProPic(),
|
||||
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.";
|
||||
return SizedBox(
|
||||
width: 400,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
bio,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
//fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget founderProPic() {
|
||||
String heading = "Yasien Meth (Founder & CEO)";
|
||||
ImageProvider logoFrame =
|
||||
MzanziInnovationHub.of(context)!.theme.altLogoFrame();
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
heading,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
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),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget mihSocials() {
|
||||
String heading = "MIH Socials";
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
heading,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: 500,
|
||||
height: 300,
|
||||
child: GridView.builder(
|
||||
padding: 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(HomeTile(
|
||||
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(HomeTile(
|
||||
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(HomeTile(
|
||||
onTap: () {
|
||||
//TODO
|
||||
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(HomeTile(
|
||||
onTap: () {
|
||||
//TODO
|
||||
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(HomeTile(
|
||||
onTap: () {
|
||||
//TODO
|
||||
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(HomeTile(
|
||||
onTap: () {
|
||||
//TODO
|
||||
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(),
|
||||
header: getHeader(),
|
||||
body: getBody(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,398 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_Action.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_Body.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_Header.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_LayoutBuilder.dart';
|
||||
import 'package:patient_manager/components/builders/buildAccessRequestList.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihDropdownInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:patient_manager/objects/accessRequest.dart';
|
||||
import 'package:patient_manager/objects/appUser.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
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<AccessRequest>> accessRequestResults;
|
||||
|
||||
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();
|
||||
// });
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: Icons.arrow_back,
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MIHHeader getHeader() {
|
||||
return const MIHHeader(
|
||||
headerAlignment: MainAxisAlignment.center,
|
||||
headerItems: [
|
||||
Text(
|
||||
"Access Reviews",
|
||||
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"
|
||||
],
|
||||
required: true,
|
||||
editable: true,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
forceRefresh = true;
|
||||
});
|
||||
refreshList();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.refresh,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder(
|
||||
future: accessRequestResults,
|
||||
builder: (context, snapshot) {
|
||||
//print("patient Queue List ${snapshot.hasData}");
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return 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,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
filterController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
selectedDropdown = "All";
|
||||
filterController.text = "All";
|
||||
filterController.addListener(refreshList);
|
||||
setState(() {
|
||||
accessRequestResults = fetchAccessRequests();
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MIHLayoutBuilder(
|
||||
actionButton: getActionButton(),
|
||||
header: getHeader(),
|
||||
body: getBody(),
|
||||
);
|
||||
// return Scaffold(
|
||||
// // appBar: const MIHAppBar(
|
||||
// // barTitle: "Access Reviews",
|
||||
// // propicFile: null,
|
||||
// // ),
|
||||
// //drawer: MIHAppDrawer(signedInUser: widget.signedInUser),
|
||||
// body: SafeArea(
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// viewAccessRequest(screenWidth, screenHeight),
|
||||
// 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(
|
||||
// onPressed: () {
|
||||
// setState(() {
|
||||
// forceRefresh = true;
|
||||
// });
|
||||
// refreshList();
|
||||
// },
|
||||
// icon: const Icon(
|
||||
// Icons.refresh,
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihTextInput.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihButton.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihSuccessMessage.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:supabase_auth_ui/supabase_auth_ui.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
emailController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
validateInput();
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
//backgroundColor: Colors.white,
|
||||
body: Stack(
|
||||
children: [
|
||||
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();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
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,375 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihPassInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihSuccessMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihTextInput.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihButton.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
//import 'package:patient_manager/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';
|
||||
|
||||
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'^[a-zA-Z0-9]+@[a-zA-Z.-]+\.[a-zA-Z]{2,}$');
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
emailController.dispose();
|
||||
passwordController.dispose();
|
||||
officeID.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
validateInput();
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
//backgroundColor: Colors.white,
|
||||
body: 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,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihPassInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihButton.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihSuccessMessage.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:supabase_auth_ui/supabase_auth_ui.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
passwordController.dispose();
|
||||
confirmPasswordController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
validateInput();
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
//backgroundColor: Colors.white,
|
||||
body: Stack(
|
||||
children: [
|
||||
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();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 10,
|
||||
left: 5,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
//Navigator.of(context).pop();
|
||||
Navigator.of(context).pushReplacementNamed('/');
|
||||
},
|
||||
icon: const Icon(Icons.login),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/homeTile.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihPassInput.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihTextInput.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihButton.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:supabase_auth_ui/supabase_auth_ui.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
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;
|
||||
// focus node to capture keyboard events
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
|
||||
late List<HomeTile> 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<HomeTile> tileList) {
|
||||
tileList.add(HomeTile(
|
||||
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(HomeTile(
|
||||
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(HomeTile(
|
||||
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) {
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@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 KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
validateInput();
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
//backgroundColor: Colors.white,
|
||||
body: 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(
|
||||
'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,
|
||||
),
|
||||
),
|
||||
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
//password input
|
||||
SizedBox(
|
||||
width: 500.0,
|
||||
child: MIHPassField(
|
||||
controller: passwordController,
|
||||
hintText: 'Password',
|
||||
required: true,
|
||||
signIn: true,
|
||||
),
|
||||
),
|
||||
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: [
|
||||
const Text(
|
||||
'New User?',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Color.fromARGB(255, 201, 200, 200)),
|
||||
),
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
320
Frontend/patient_manager/lib/MIH_Packages/fullScreenFile.dart
Normal file
320
Frontend/patient_manager/lib/MIH_Packages/fullScreenFile.dart
Normal file
@@ -0,0 +1,320 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:patient_manager/objects/arguments.dart';
|
||||
import 'package:syncfusion_flutter_core/theme.dart';
|
||||
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
|
||||
import "package:universal_html/html.dart" as html;
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
pdfViewerController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
pdfViewerController.addListener(onPageSelect);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Size size = MediaQuery.sizeOf(context);
|
||||
double width = size.width;
|
||||
double height = size.height;
|
||||
|
||||
if (getExtType(widget.arguments.path).toLowerCase() == "pdf") {
|
||||
return Scaffold(
|
||||
body: SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
width: width,
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
decoration: BoxDecoration(
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 50),
|
||||
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;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
left: 2,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.fullscreen_exit,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
right: 2,
|
||||
//width: 50,
|
||||
height: 50,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
pdfViewerController.previousPage();
|
||||
//print(pdfViewerController.);
|
||||
//if (pdfViewerController.pageNumber > 1) {
|
||||
setState(() {
|
||||
currentPage = pdfViewerController.pageNumber;
|
||||
});
|
||||
// }
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.arrow_back,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
// SizedBox(
|
||||
// width: 40,
|
||||
// height: 40,
|
||||
// child: MIHTextField(
|
||||
// controller: cuntrController,
|
||||
// hintText: "",
|
||||
// editable: true,
|
||||
// required: false),
|
||||
// ),
|
||||
Text(
|
||||
"$currentPage / $currentPageCount",
|
||||
style: const TextStyle(fontSize: 20),
|
||||
),
|
||||
IconButton(
|
||||
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(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
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(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
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(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
html.window.open(
|
||||
widget.arguments.link,
|
||||
// '${AppEnviroment.baseFileUrl}/mih/$filePath',
|
||||
'download');
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.download,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(top: 50.0),
|
||||
width: width,
|
||||
// height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
//borderRadius: BorderRadius.circular(25.0),
|
||||
// border: Border.all(
|
||||
// color: MzanziInnovationHub.of(context)!.theme.errorColor(),
|
||||
// width: 5.0),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
Expanded(
|
||||
child: InteractiveViewer(
|
||||
maxScale: 5.0,
|
||||
//minScale: 0.,
|
||||
child: Image.network(widget.arguments.link),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
left: 2,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.fullscreen_exit,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
right: 2,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
html.window.open(
|
||||
widget.arguments.link,
|
||||
// '${AppEnviroment.baseFileUrl}/mih/$filePath',
|
||||
'download');
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.download,
|
||||
color:
|
||||
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
151
Frontend/patient_manager/lib/MIH_Packages/home.dart
Normal file
151
Frontend/patient_manager/lib/MIH_Packages/home.dart
Normal file
@@ -0,0 +1,151 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/components/homeTileGrid.dart';
|
||||
import 'package:patient_manager/objects/appUser.dart';
|
||||
import 'package:patient_manager/objects/arguments.dart';
|
||||
import 'package:patient_manager/objects/business.dart';
|
||||
import 'package:patient_manager/objects/businessUser.dart';
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
class Home extends StatefulWidget {
|
||||
const Home({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<Home> createState() => _HomeState();
|
||||
}
|
||||
|
||||
class _HomeState extends State<Home> {
|
||||
String useremail = "";
|
||||
final baseAPI = AppEnviroment.baseApiUrl;
|
||||
late Future<HomeArguments> profile;
|
||||
|
||||
String proPicUrl = "empty";
|
||||
ImageProvider<Object>? propicFile;
|
||||
|
||||
Future<HomeArguments> getProfile() async {
|
||||
AppUser userData;
|
||||
Business? busData;
|
||||
BusinessUser? bUserData;
|
||||
String userPic;
|
||||
|
||||
// Get Userdata
|
||||
var uid = await SuperTokens.getUserId();
|
||||
var responseUser = await http.get(Uri.parse("$baseAPI/user/$uid"));
|
||||
if (responseUser.statusCode == 200) {
|
||||
// print("here");
|
||||
String body = responseUser.body;
|
||||
var decodedData = jsonDecode(body);
|
||||
AppUser u = AppUser.fromJson(decodedData);
|
||||
userData = u;
|
||||
} else {
|
||||
throw Exception(
|
||||
"Error: GetUserData status code ${responseUser.statusCode}");
|
||||
}
|
||||
|
||||
// Get BusinessUserdata
|
||||
var responseBUser =
|
||||
await http.get(Uri.parse("$baseAPI/business-user/$uid"));
|
||||
if (responseBUser.statusCode == 200) {
|
||||
String body = responseBUser.body;
|
||||
var decodedData = jsonDecode(body);
|
||||
BusinessUser business_User = BusinessUser.fromJson(decodedData);
|
||||
bUserData = business_User;
|
||||
} else {
|
||||
bUserData = null;
|
||||
}
|
||||
|
||||
// Get Businessdata
|
||||
var responseBusiness =
|
||||
await http.get(Uri.parse("$baseAPI/business/app_id/$uid"));
|
||||
if (responseBusiness.statusCode == 200) {
|
||||
String body = responseBusiness.body;
|
||||
var decodedData = jsonDecode(body);
|
||||
Business business = Business.fromJson(decodedData);
|
||||
busData = business;
|
||||
} else {
|
||||
busData = null;
|
||||
}
|
||||
|
||||
//get profile picture
|
||||
if (userData.pro_pic_path == "") {
|
||||
userPic = "";
|
||||
}
|
||||
// else if (AppEnviroment.getEnv() == "Dev") {
|
||||
// userPic = "${AppEnviroment.baseFileUrl}/mih/${userData.pro_pic_path}";
|
||||
// }
|
||||
else {
|
||||
var url =
|
||||
"${AppEnviroment.baseApiUrl}/minio/pull/file/${AppEnviroment.getEnv()}/${userData.pro_pic_path}";
|
||||
var response = await http.get(Uri.parse(url));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
String body = response.body;
|
||||
var decodedData = jsonDecode(body);
|
||||
|
||||
userPic = decodedData['minioURL'];
|
||||
} else {
|
||||
userPic = "";
|
||||
// throw Exception(
|
||||
// "Error: GetUserData status code ${response.statusCode}");
|
||||
}
|
||||
}
|
||||
//print(userPic);
|
||||
return HomeArguments(userData, bUserData, busData, userPic);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// <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();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: profile,
|
||||
builder: (BuildContext context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.hasData) {
|
||||
return HomeTileGrid(
|
||||
signedInUser: snapshot.requireData.signedInUser,
|
||||
businessUser: snapshot.data!.businessUser,
|
||||
business: snapshot.data!.business,
|
||||
propicFile: isPictureAvailable(snapshot.data!.profilePicUrl),
|
||||
);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
'${snapshot.error} occurred',
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
return const Mihloadingcircle();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,484 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/builders/buildEmployeeList.dart';
|
||||
import 'package:patient_manager/components/builders/buildUserList.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihSearchInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihSuccessMessage.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:patient_manager/objects/appUser.dart';
|
||||
import 'package:patient_manager/objects/arguments.dart';
|
||||
import 'package:patient_manager/objects/businessEmployee.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
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(double w, double h) {
|
||||
return SizedBox(
|
||||
width: w,
|
||||
height: h - 157,
|
||||
child: Column(mainAxisSize: MainAxisSize.max, children: [
|
||||
const Text(
|
||||
"Business Team",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
FutureBuilder(
|
||||
future: employeeList,
|
||||
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<BusinessEmployee> employeeListResults;
|
||||
// if (searchString == "") {
|
||||
// patientQueueList = [];
|
||||
// } else {
|
||||
|
||||
// print(patientQueueList);
|
||||
// }
|
||||
|
||||
return Expanded(
|
||||
child: displayEmployeeList(snapshot.requireData),
|
||||
);
|
||||
} else {
|
||||
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: 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 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: BuildEmployeeList(
|
||||
employees: employeeList,
|
||||
arguments: widget.arguments,
|
||||
),
|
||||
);
|
||||
}
|
||||
return 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: 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 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: BuildUserList(
|
||||
users: userList,
|
||||
arguments: widget.arguments,
|
||||
),
|
||||
);
|
||||
}
|
||||
return 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: 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(double w, double h) {
|
||||
return KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
submitUserForm();
|
||||
}
|
||||
},
|
||||
child: SizedBox(
|
||||
width: w,
|
||||
height: h - 157,
|
||||
child: Column(mainAxisSize: MainAxisSize.max, children: [
|
||||
const SizedBox(height: 5),
|
||||
const Text(
|
||||
"User Search",
|
||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||
),
|
||||
//spacer
|
||||
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 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 &&
|
||||
snapshot.hasData) {
|
||||
List<AppUser> patientsList;
|
||||
if (userSearch == "") {
|
||||
patientsList = [];
|
||||
} else {
|
||||
patientsList = snapshot.data!;
|
||||
//print(patientsList);
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: displayUserList(patientsList),
|
||||
);
|
||||
} else {
|
||||
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: 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, double screenWidth, double screenHeight) {
|
||||
if (selectionIndex == 0) {
|
||||
return SizedBox(
|
||||
//width: 660,
|
||||
child: employeesview(screenWidth, screenHeight),
|
||||
);
|
||||
} else {
|
||||
return userSearchView(screenWidth, screenHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
searchController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
userSearchResults = fetchUsers("abc");
|
||||
employeeList = fetchEmployees();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final screenHeight = MediaQuery.of(context).size.height;
|
||||
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,418 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_Action.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_Body.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_Header.dart';
|
||||
import 'package:patient_manager/components/MIH_Layout/MIH_LayoutBuilder.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihFileInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihSuccessMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihTextInput.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihButton.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:patient_manager/objects/arguments.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
import 'package:http/http.dart' as http2;
|
||||
import 'package:supertokens_flutter/supertokens.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();
|
||||
|
||||
late 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 {
|
||||
//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");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget displayProPic() {
|
||||
ImageProvider logoFrame =
|
||||
MzanziInnovationHub.of(context)!.theme.altLogoFrame();
|
||||
if (widget.arguments.propicFile != null) {
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
fit: StackFit.loose,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
backgroundColor:
|
||||
MzanziInnovationHub.of(context)!.theme.primaryColor(),
|
||||
backgroundImage: propicPreview,
|
||||
//'https://media.licdn.com/dms/image/D4D03AQGd1-QhjtWWpA/profile-displayphoto-shrink_400_400/0/1671698053061?e=2147483647&v=beta&t=a3dJI5yxs5-KeXjj10LcNCFuC9IOfa8nNn3k_Qyr0CA'),
|
||||
radius: 50,
|
||||
),
|
||||
SizedBox(
|
||||
width: 110,
|
||||
child: Image(image: logoFrame),
|
||||
)
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return SizedBox(
|
||||
width: 60,
|
||||
child: Image(image: logoFrame),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MIHAction getActionButton() {
|
||||
return MIHAction(
|
||||
icon: Icons.arrow_back,
|
||||
iconSize: 35,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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(),
|
||||
const SizedBox(height: 25.0),
|
||||
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(),
|
||||
body: getBody(),
|
||||
);
|
||||
}
|
||||
}
|
||||
381
Frontend/patient_manager/lib/MIH_Packages/patientAdd.dart
Normal file
381
Frontend/patient_manager/lib/MIH_Packages/patientAdd.dart
Normal file
@@ -0,0 +1,381 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihDropdownInput.dart';
|
||||
//import 'package:patient_manager/components/mihAppDrawer.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihSuccessMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihTextInput.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihButton.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:patient_manager/objects/appUser.dart';
|
||||
import 'package:patient_manager/objects/arguments.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
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(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
"Personal Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25.0,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25.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: 25.0,
|
||||
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");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@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 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),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
645
Frontend/patient_manager/lib/MIH_Packages/patientEdit.dart
Normal file
645
Frontend/patient_manager/lib/MIH_Packages/patientEdit.dart
Normal file
@@ -0,0 +1,645 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihDropdownInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihSuccessMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihTextInput.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihButton.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:patient_manager/objects/appUser.dart';
|
||||
import 'package:patient_manager/objects/arguments.dart';
|
||||
import 'package:patient_manager/objects/patients.dart';
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
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(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
"Personal Details",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 25.0,
|
||||
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25.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: 25.0,
|
||||
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");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@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 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();
|
||||
},
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
536
Frontend/patient_manager/lib/MIH_Packages/patientManager.dart
Normal file
536
Frontend/patient_manager/lib/MIH_Packages/patientManager.dart
Normal file
@@ -0,0 +1,536 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/builders/buildPatientList.dart';
|
||||
import 'package:patient_manager/components/builders/buildPatientQueueList.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihDateInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/objects/arguments.dart';
|
||||
import 'package:patient_manager/objects/patientQueue.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihSearchInput.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:patient_manager/objects/patients.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 queueDateController = TextEditingController();
|
||||
|
||||
String baseUrl = AppEnviroment.baseApiUrl;
|
||||
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
String errorCode = "";
|
||||
String errorBody = "";
|
||||
|
||||
String searchString = "";
|
||||
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<PatientQueue>> patientQueueResults;
|
||||
|
||||
Future<List<PatientQueue>> fetchPatientQueue(String date) async {
|
||||
//print("Patien manager page: $endpoint");
|
||||
final response = await http.get(Uri.parse(
|
||||
"$baseUrl/queue/patients/${widget.arguments.businessUser!.business_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<PatientQueue> patientQueue = List<PatientQueue>.from(
|
||||
l.map((model) => PatientQueue.fromJson(model)));
|
||||
//print("Here3");
|
||||
//print(patientQueue);
|
||||
return patientQueue;
|
||||
} else {
|
||||
throw Exception('failed to load patients');
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Future<List<Patient>> fetchPatients(String search) async {
|
||||
final response =
|
||||
await http.get(Uri.parse("$baseUrl/patients/search/$search"));
|
||||
errorCode = response.statusCode.toString();
|
||||
errorBody = response.body;
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Iterable l = jsonDecode(response.body);
|
||||
List<Patient> patients =
|
||||
List<Patient>.from(l.map((model) => Patient.fromJson(model)));
|
||||
return patients;
|
||||
} else {
|
||||
throw Exception('failed to load patients');
|
||||
}
|
||||
}
|
||||
|
||||
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 (searchString.isNotEmpty && searchString != "") {
|
||||
return 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: BuildPatientsList(
|
||||
patients: patientsList,
|
||||
signedInUser: widget.arguments.signedInUser,
|
||||
business: widget.arguments.business,
|
||||
arguments: widget.arguments,
|
||||
),
|
||||
);
|
||||
}
|
||||
return 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: 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(double w, double h) {
|
||||
return KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
submitPatientForm();
|
||||
}
|
||||
},
|
||||
child: SizedBox(
|
||||
width: w,
|
||||
height: h - 157,
|
||||
child: Column(mainAxisSize: MainAxisSize.max, children: [
|
||||
const SizedBox(height: 5),
|
||||
const Text(
|
||||
"Patient Search",
|
||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
MIHSearchField(
|
||||
controller: searchController,
|
||||
hintText: "ID or Medical Aid No. Search",
|
||||
required: true,
|
||||
editable: true,
|
||||
onTap: () {
|
||||
submitPatientForm();
|
||||
},
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder(
|
||||
future: patientSearchResults,
|
||||
builder: (context, snapshot) {
|
||||
//print("patient Liust ${snapshot.data}");
|
||||
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 &&
|
||||
snapshot.hasData) {
|
||||
List<Patient> patientsList;
|
||||
if (searchString == "") {
|
||||
patientsList = [];
|
||||
} else {
|
||||
patientsList =
|
||||
filterSearchResults(snapshot.data!, searchString);
|
||||
//print(patientsList);
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: displayPatientList(patientsList, searchString),
|
||||
);
|
||||
} else {
|
||||
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: Center(
|
||||
child: Text(
|
||||
"$errorCode: Error pulling Patients Data\n$baseUrl/patients/search/$searchString\n$errorBody",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.errorColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget displayQueueList(List<PatientQueue> patientQueueList) {
|
||||
if (patientQueueList.isNotEmpty) {
|
||||
return 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: BuildPatientQueueList(
|
||||
patientQueue: patientQueueList,
|
||||
signedInUser: widget.arguments.signedInUser,
|
||||
business: widget.arguments.business,
|
||||
businessUser: widget.arguments.businessUser,
|
||||
),
|
||||
);
|
||||
}
|
||||
return 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: Center(
|
||||
child: Text(
|
||||
"No Appointments for $formattedDate",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!.theme.messageTextColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget patientQueue(double w, double h) {
|
||||
return SizedBox(
|
||||
width: w,
|
||||
height: h - 157,
|
||||
child: Column(mainAxisSize: MainAxisSize.max, children: [
|
||||
//const SizedBox(height: 15),
|
||||
const Text(
|
||||
"Waiting Room",
|
||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MIHDateField(
|
||||
controller: queueDateController,
|
||||
LableText: "Date",
|
||||
required: true,
|
||||
),
|
||||
//spacer
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder(
|
||||
future: patientQueueResults,
|
||||
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<PatientQueue> patientQueueList;
|
||||
// if (searchString == "") {
|
||||
// patientQueueList = [];
|
||||
// } else {
|
||||
patientQueueList = filterQueueResults(
|
||||
snapshot.requireData, queueDateController.text);
|
||||
// print(patientQueueList);
|
||||
// }
|
||||
|
||||
return Expanded(
|
||||
child: displayQueueList(patientQueueList),
|
||||
);
|
||||
} else {
|
||||
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: Center(
|
||||
child: Text(
|
||||
"$errorCode: Error pulling Patients Data\n$baseUrl/patients/search/$searchString\n$errorBody",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.errorColor()),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void refreshQueue() {
|
||||
setState(() {
|
||||
start = true;
|
||||
});
|
||||
checkforchange();
|
||||
}
|
||||
|
||||
void submitPatientForm() {
|
||||
if (searchController.text != "") {
|
||||
setState(() {
|
||||
searchString = searchController.text;
|
||||
patientSearchResults = fetchPatients(searchString);
|
||||
});
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const MIHErrorMessage(errorType: "Input Error");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void checkforchange() {
|
||||
if (start == true) {
|
||||
setState(() {
|
||||
patientQueueResults = fetchPatientQueue(queueDateController.text);
|
||||
start = false;
|
||||
});
|
||||
}
|
||||
if (formattedDate != queueDateController.text) {
|
||||
setState(() {
|
||||
patientQueueResults = fetchPatientQueue(queueDateController.text);
|
||||
formattedDate = queueDateController.text;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget showSelection(int index, double screenWidth, double screenHeight) {
|
||||
if (index == 0) {
|
||||
return SizedBox(
|
||||
//width: 660,
|
||||
child: patientQueue(screenWidth, screenHeight),
|
||||
);
|
||||
} else {
|
||||
return SizedBox(
|
||||
//width: 660,
|
||||
child: patientSearch(screenWidth, screenHeight),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
searchController.dispose();
|
||||
queueDateController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
patientSearchResults = fetchPatients("abc");
|
||||
queueDateController.addListener(checkforchange);
|
||||
setState(() {
|
||||
formattedDate = formatter.format(now);
|
||||
queueDateController.text = formattedDate;
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final screenHeight = MediaQuery.of(context).size.height;
|
||||
return Scaffold(
|
||||
// appBar: const MIHAppBar(
|
||||
// barTitle: "Patient Manager",
|
||||
// propicFile: null,
|
||||
// ),
|
||||
body: Stack(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 5),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 0;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.people,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 1;
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.search,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
refreshQueue();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.refresh,
|
||||
size: 35,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||
child: showSelection(_selectedIndex, screenWidth, screenHeight),
|
||||
),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
left: 5,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
194
Frontend/patient_manager/lib/MIH_Packages/patientView.dart
Normal file
194
Frontend/patient_manager/lib/MIH_Packages/patientView.dart
Normal file
@@ -0,0 +1,194 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:patient_manager/components/patientDetails.dart';
|
||||
import 'package:patient_manager/components/patientFiles.dart';
|
||||
import 'package:patient_manager/components/patientNotes.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:patient_manager/objects/arguments.dart';
|
||||
import 'package:patient_manager/objects/patients.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@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 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),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihDropdownInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihFileInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihSuccessMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihTextInput.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihButton.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:patient_manager/objects/appUser.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;
|
||||
|
||||
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();
|
||||
|
||||
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,
|
||||
}),
|
||||
);
|
||||
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'^[a-zA-Z0-9]+@[a-zA-Z.-]+\.[a-zA-Z]{2,}$');
|
||||
return regex.hasMatch(text);
|
||||
}
|
||||
|
||||
@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(() {
|
||||
fnameController.text = widget.signedInUser.fname;
|
||||
lnameController.text = widget.signedInUser.lname;
|
||||
accessController.text = "Full";
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
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),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,524 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihLoadingCircle.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihDropdownInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihErrorMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihFileInput.dart';
|
||||
import 'package:patient_manager/components/popUpMessages/mihSuccessMessage.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihTextInput.dart';
|
||||
import 'package:patient_manager/components/inputsAndButtons/mihButton.dart';
|
||||
import 'package:patient_manager/env/env.dart';
|
||||
import 'package:patient_manager/main.dart';
|
||||
import 'package:patient_manager/objects/arguments.dart';
|
||||
import 'package:supertokens_flutter/http.dart' as http;
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
import 'package:http/http.dart' as http2;
|
||||
|
||||
class ProfileBusinessUpdate extends StatefulWidget {
|
||||
final BusinessArguments arguments;
|
||||
const ProfileBusinessUpdate({
|
||||
super.key,
|
||||
required this.arguments,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ProfileBusinessUpdate> createState() => _ProfileBusinessUpdateState();
|
||||
}
|
||||
|
||||
class BusinessUserScreenArguments {}
|
||||
|
||||
class _ProfileBusinessUpdateState extends State<ProfileBusinessUpdate> {
|
||||
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?> 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,
|
||||
}),
|
||||
);
|
||||
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 Scaffold(
|
||||
// appBar: const MIHAppBar(
|
||||
// barTitle: "Business Profile",
|
||||
// propicFile: null,
|
||||
// ),
|
||||
//drawer: MIHAppDrawer(signedInUser: widget.arguments.signedInUser),
|
||||
body: SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
KeyboardListener(
|
||||
focusNode: _focusNode,
|
||||
autofocus: true,
|
||||
onKeyEvent: (event) async {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
//print(business_id);
|
||||
submitForm(business_id);
|
||||
}
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: Column(
|
||||
children: [
|
||||
Visibility(
|
||||
visible: isFullAccess(),
|
||||
child: Column(
|
||||
children: [
|
||||
const Text(
|
||||
"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(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
//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: "Update",
|
||||
buttonColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
textColor: MzanziInnovationHub.of(context)!
|
||||
.theme
|
||||
.primaryColor(),
|
||||
onTap: () {
|
||||
//print(business_id);
|
||||
submitForm(business_id);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 10,
|
||||
left: 5,
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user