NEW: Privacy Policy and TOS Popup
This commit is contained in:
@@ -37,6 +37,8 @@ PODS:
|
|||||||
- file_picker (0.0.1):
|
- file_picker (0.0.1):
|
||||||
- DKImagePickerController/PhotoGallery
|
- DKImagePickerController/PhotoGallery
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- file_saver (0.0.1):
|
||||||
|
- Flutter
|
||||||
- fl_downloader (0.0.1):
|
- fl_downloader (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
@@ -93,6 +95,7 @@ DEPENDENCIES:
|
|||||||
- app_settings (from `.symlinks/plugins/app_settings/ios`)
|
- app_settings (from `.symlinks/plugins/app_settings/ios`)
|
||||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||||
|
- file_saver (from `.symlinks/plugins/file_saver/ios`)
|
||||||
- fl_downloader (from `.symlinks/plugins/fl_downloader/ios`)
|
- fl_downloader (from `.symlinks/plugins/fl_downloader/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||||
@@ -128,6 +131,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||||
file_picker:
|
file_picker:
|
||||||
:path: ".symlinks/plugins/file_picker/ios"
|
:path: ".symlinks/plugins/file_picker/ios"
|
||||||
|
file_saver:
|
||||||
|
:path: ".symlinks/plugins/file_saver/ios"
|
||||||
fl_downloader:
|
fl_downloader:
|
||||||
:path: ".symlinks/plugins/fl_downloader/ios"
|
:path: ".symlinks/plugins/fl_downloader/ios"
|
||||||
Flutter:
|
Flutter:
|
||||||
@@ -171,6 +176,7 @@ SPEC CHECKSUMS:
|
|||||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||||
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
||||||
|
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
||||||
fl_downloader: dc99aa8dd303f862cccb830087f37acc9b0156ee
|
fl_downloader: dc99aa8dd303f862cccb830087f37acc9b0156ee
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
|
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
|
||||||
|
|||||||
29
Frontend/lib/mih_components/mih_objects/user_consent.dart
Normal file
29
Frontend/lib/mih_components/mih_objects/user_consent.dart
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
class UserConsent {
|
||||||
|
String app_id;
|
||||||
|
DateTime privacy_policy_accepted;
|
||||||
|
DateTime terms_of_services_accepted;
|
||||||
|
|
||||||
|
UserConsent({
|
||||||
|
required this.app_id,
|
||||||
|
required this.privacy_policy_accepted,
|
||||||
|
required this.terms_of_services_accepted,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory UserConsent.fromJson(Map<String, dynamic> json) {
|
||||||
|
return UserConsent(
|
||||||
|
app_id: json['app_id'],
|
||||||
|
privacy_policy_accepted: DateTime.parse(json['privacy_policy_accepted']),
|
||||||
|
terms_of_services_accepted:
|
||||||
|
DateTime.parse(json['terms_of_services_accepted']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'app_id': app_id,
|
||||||
|
'privacy_policy_accepted': privacy_policy_accepted.toIso8601String(),
|
||||||
|
'terms_of_services_accepted':
|
||||||
|
terms_of_services_accepted.toIso8601String(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:mzansi_innovation_hub/main.dart';
|
import 'package:mzansi_innovation_hub/main.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
||||||
@@ -99,7 +100,7 @@ class _MihPackageAlertState extends State<MihPackageAlert> {
|
|||||||
height: 50,
|
height: 50,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
context.pop();
|
||||||
},
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.close,
|
Icons.close,
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:ken_logger/ken_logger.dart';
|
||||||
import 'package:mzansi_innovation_hub/main.dart';
|
import 'package:mzansi_innovation_hub/main.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
|
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
|
||||||
|
import 'package:mzansi_innovation_hub/mih_components/mih_objects/user_consent.dart';
|
||||||
|
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart';
|
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart';
|
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart';
|
||||||
|
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart';
|
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart';
|
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart';
|
import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart';
|
||||||
|
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart';
|
||||||
|
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_scack_bar.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_config/mih_env.dart';
|
import 'package:mzansi_innovation_hub/mih_config/mih_env.dart';
|
||||||
@@ -14,32 +21,13 @@ import 'package:mzansi_innovation_hub/mih_packages/mih_home/package_tools/mih_bu
|
|||||||
import 'package:mzansi_innovation_hub/mih_packages/mih_home/package_tools/mih_personal_home.dart';
|
import 'package:mzansi_innovation_hub/mih_packages/mih_home/package_tools/mih_personal_home.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_services/mih_service_calls.dart';
|
import 'package:mzansi_innovation_hub/mih_services/mih_service_calls.dart';
|
||||||
|
import 'package:mzansi_innovation_hub/mih_services/mih_user_consent_services.dart';
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class MihHome extends StatefulWidget {
|
class MihHome extends StatefulWidget {
|
||||||
// final AppUser signedInUser;
|
|
||||||
// final BusinessUser? businessUser;
|
|
||||||
// final Business? business;
|
|
||||||
// final Patient? patient;
|
|
||||||
// final List<MIHNotification> notifications;
|
|
||||||
// final ImageProvider<Object>? propicFile;
|
|
||||||
// final bool isUserNew;
|
|
||||||
// final bool isBusinessUser;
|
|
||||||
// final bool isBusinessUserNew;
|
|
||||||
// final bool isDevActive;
|
|
||||||
final bool personalSelected;
|
final bool personalSelected;
|
||||||
const MihHome({
|
const MihHome({
|
||||||
super.key,
|
super.key,
|
||||||
// required this.signedInUser,
|
|
||||||
// required this.businessUser,
|
|
||||||
// required this.business,
|
|
||||||
// required this.patient,
|
|
||||||
// required this.notifications,
|
|
||||||
// required this.propicFile,
|
|
||||||
// required this.isUserNew,
|
|
||||||
// required this.isBusinessUser,
|
|
||||||
// required this.isBusinessUserNew,
|
|
||||||
// required this.isDevActive,
|
|
||||||
required this.personalSelected,
|
required this.personalSelected,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -52,6 +40,79 @@ class _MihHomeState extends State<MihHome> {
|
|||||||
late int _selcetedIndex;
|
late int _selcetedIndex;
|
||||||
late bool _personalSelected;
|
late bool _personalSelected;
|
||||||
late Future<HomeArguments> profileData;
|
late Future<HomeArguments> profileData;
|
||||||
|
late Future<UserConsent?> futureUserConsent;
|
||||||
|
bool showUserConsent = false;
|
||||||
|
DateTime latestPrivacyPolicyDate = DateTime.parse("2024-12-01");
|
||||||
|
DateTime latestTermOfServiceDate = DateTime.parse("2024-12-01");
|
||||||
|
|
||||||
|
bool showPolicyWindow(UserConsent? userConsent) {
|
||||||
|
if (userConsent == null) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (userConsent.privacy_policy_accepted
|
||||||
|
.isAfter(latestPrivacyPolicyDate) &&
|
||||||
|
userConsent.terms_of_services_accepted
|
||||||
|
.isAfter(latestTermOfServiceDate)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createOrUpdateAccpetance(UserConsent? userConsent, String app_id) {
|
||||||
|
userConsent != null
|
||||||
|
? MihUserConsentServices()
|
||||||
|
.updateUserConsentStatus(
|
||||||
|
app_id,
|
||||||
|
DateTime.now().toIso8601String(),
|
||||||
|
DateTime.now().toIso8601String(),
|
||||||
|
)
|
||||||
|
.then((value) {
|
||||||
|
if (value == 200) {
|
||||||
|
// setState(() {
|
||||||
|
// showUserConsent = false;
|
||||||
|
// });
|
||||||
|
context.goNamed("mihHome", extra: false);
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
MihSnackBar(
|
||||||
|
child: Text("Thank you for accepting our Policies"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
MihSnackBar(
|
||||||
|
child: Text("There was an error, please try again later"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
: MihUserConsentServices()
|
||||||
|
.insertUserConsentStatus(
|
||||||
|
app_id,
|
||||||
|
DateTime.now().toIso8601String(),
|
||||||
|
DateTime.now().toIso8601String(),
|
||||||
|
)
|
||||||
|
.then((value) {
|
||||||
|
if (value == 201) {
|
||||||
|
// setState(() {
|
||||||
|
// showUserConsent = false;
|
||||||
|
// });
|
||||||
|
context.goNamed("mihHome", extra: false);
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
MihSnackBar(
|
||||||
|
child: Text("Thank you for accepting our Policies"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
MihSnackBar(
|
||||||
|
child: Text("There was an error, please try again later"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
@@ -62,6 +123,7 @@ class _MihHomeState extends State<MihHome> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
profileData = MIHApiCalls().getProfile(10, context);
|
profileData = MIHApiCalls().getProfile(10, context);
|
||||||
|
futureUserConsent = MihUserConsentServices().getUserConsentStatus();
|
||||||
if (widget.personalSelected == true) {
|
if (widget.personalSelected == true) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selcetedIndex = 0;
|
_selcetedIndex = 0;
|
||||||
@@ -96,30 +158,259 @@ class _MihHomeState extends State<MihHome> {
|
|||||||
);
|
);
|
||||||
} else if (asyncSnapshot.connectionState == ConnectionState.done &&
|
} else if (asyncSnapshot.connectionState == ConnectionState.done &&
|
||||||
asyncSnapshot.hasData) {
|
asyncSnapshot.hasData) {
|
||||||
return MihPackage(
|
return Stack(
|
||||||
appActionButton: getAction(asyncSnapshot.data!.profilePicUrl),
|
children: [
|
||||||
appTools:
|
MihPackage(
|
||||||
getTools(asyncSnapshot.data!.signedInUser.type != "personal"),
|
appActionButton: getAction(asyncSnapshot.data!.profilePicUrl),
|
||||||
appBody: getToolBody(asyncSnapshot.data!),
|
appTools: getTools(
|
||||||
appToolTitles: getToolTitle(),
|
asyncSnapshot.data!.signedInUser.type != "personal"),
|
||||||
actionDrawer: getActionDrawer(
|
appBody: getToolBody(asyncSnapshot.data!),
|
||||||
asyncSnapshot.data!.signedInUser,
|
appToolTitles: getToolTitle(),
|
||||||
asyncSnapshot.data!.profilePicUrl,
|
actionDrawer: getActionDrawer(
|
||||||
),
|
asyncSnapshot.data!.signedInUser,
|
||||||
selectedbodyIndex: _selcetedIndex,
|
asyncSnapshot.data!.profilePicUrl,
|
||||||
onIndexChange: (newValue) {
|
),
|
||||||
if (_selcetedIndex == 0) {
|
selectedbodyIndex: _selcetedIndex,
|
||||||
setState(() {
|
onIndexChange: (newValue) {
|
||||||
_selcetedIndex = newValue;
|
if (_selcetedIndex == 0) {
|
||||||
_personalSelected = true;
|
setState(() {
|
||||||
});
|
_selcetedIndex = newValue;
|
||||||
} else {
|
_personalSelected = true;
|
||||||
setState(() {
|
});
|
||||||
_selcetedIndex = newValue;
|
} else {
|
||||||
_personalSelected = false;
|
setState(() {
|
||||||
});
|
_selcetedIndex = newValue;
|
||||||
}
|
_personalSelected = false;
|
||||||
},
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
FutureBuilder(
|
||||||
|
future: futureUserConsent,
|
||||||
|
builder: (context, asyncSnapshotUserConsent) {
|
||||||
|
if (asyncSnapshotUserConsent.connectionState ==
|
||||||
|
ConnectionState.waiting) {
|
||||||
|
showUserConsent = false;
|
||||||
|
} else if (asyncSnapshotUserConsent.connectionState ==
|
||||||
|
ConnectionState.done &&
|
||||||
|
asyncSnapshotUserConsent.hasData) {
|
||||||
|
showUserConsent =
|
||||||
|
showPolicyWindow(asyncSnapshotUserConsent.data);
|
||||||
|
} else if (asyncSnapshotUserConsent.connectionState ==
|
||||||
|
ConnectionState.done &&
|
||||||
|
!asyncSnapshotUserConsent.hasData) {
|
||||||
|
showUserConsent = true;
|
||||||
|
} else {
|
||||||
|
showUserConsent = false;
|
||||||
|
}
|
||||||
|
return Visibility(
|
||||||
|
visible: showUserConsent,
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black.withValues(alpha: 0.5),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
MihPackageWindow(
|
||||||
|
fullscreen: false,
|
||||||
|
windowTitle:
|
||||||
|
"Privacy Policy & Terms Of Service Alert!",
|
||||||
|
onWindowTapClose: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return MihPackageAlert(
|
||||||
|
alertIcon: Icon(
|
||||||
|
Icons.warning_amber_rounded,
|
||||||
|
size: 100,
|
||||||
|
color: MihColors.getRedColor(
|
||||||
|
MzansiInnovationHub.of(context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
alertTitle:
|
||||||
|
"Oops, Looks like you missed a step!",
|
||||||
|
alertBody: Text(
|
||||||
|
"We're excited for you to keep using the MIH app! Before you do, please take a moment to accept our Privacy Policy and Terms of Service. Thanks for helping us keep your experience great!",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: MihColors.getSecondaryColor(
|
||||||
|
MzansiInnovationHub.of(context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark",
|
||||||
|
),
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
alertColour: MihColors.getRedColor(
|
||||||
|
MzansiInnovationHub.of(context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
windowBody: Column(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.policy,
|
||||||
|
size: 150,
|
||||||
|
color: MihColors.getSecondaryColor(
|
||||||
|
MzansiInnovationHub.of(context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
"Welcome to the MIH App",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: MihColors.getSecondaryColor(
|
||||||
|
MzansiInnovationHub.of(context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark",
|
||||||
|
),
|
||||||
|
fontSize: 30,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
"To keep using the MIH app, please take a moment to review and accept our Privacy Policy and Terms of Service. our agreement helps us keep things running smoothly and securely.",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: MihColors.getSecondaryColor(
|
||||||
|
MzansiInnovationHub.of(context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark",
|
||||||
|
),
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Center(
|
||||||
|
child: Wrap(
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
spacing: 10,
|
||||||
|
runSpacing: 10,
|
||||||
|
children: [
|
||||||
|
MihButton(
|
||||||
|
onPressed: () {
|
||||||
|
context.goNamed(
|
||||||
|
"aboutMih",
|
||||||
|
extra: AboutArguments(
|
||||||
|
widget.personalSelected,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
buttonColor: MihColors.getOrangeColor(
|
||||||
|
MzansiInnovationHub.of(context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark"),
|
||||||
|
elevation: 10,
|
||||||
|
width: 300,
|
||||||
|
child: Text(
|
||||||
|
"Privacy Policy",
|
||||||
|
style: TextStyle(
|
||||||
|
color: MihColors.getPrimaryColor(
|
||||||
|
MzansiInnovationHub.of(
|
||||||
|
context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark"),
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
MihButton(
|
||||||
|
onPressed: () {
|
||||||
|
context.goNamed(
|
||||||
|
"aboutMih",
|
||||||
|
extra: AboutArguments(
|
||||||
|
widget.personalSelected,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
buttonColor: MihColors.getYellowColor(
|
||||||
|
MzansiInnovationHub.of(context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark"),
|
||||||
|
elevation: 10,
|
||||||
|
width: 300,
|
||||||
|
child: Text(
|
||||||
|
"Terms of Service",
|
||||||
|
style: TextStyle(
|
||||||
|
color: MihColors.getPrimaryColor(
|
||||||
|
MzansiInnovationHub.of(
|
||||||
|
context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark"),
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
MihButton(
|
||||||
|
onPressed: () {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
KenLogger.success(
|
||||||
|
"Date Time Now: $now");
|
||||||
|
createOrUpdateAccpetance(
|
||||||
|
asyncSnapshotUserConsent.data,
|
||||||
|
asyncSnapshot
|
||||||
|
.data!.signedInUser.app_id,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
buttonColor: MihColors.getGreenColor(
|
||||||
|
MzansiInnovationHub.of(context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark"),
|
||||||
|
elevation: 10,
|
||||||
|
width: 300,
|
||||||
|
child: Text(
|
||||||
|
"Accept",
|
||||||
|
style: TextStyle(
|
||||||
|
color: MihColors.getPrimaryColor(
|
||||||
|
MzansiInnovationHub.of(
|
||||||
|
context)!
|
||||||
|
.theme
|
||||||
|
.mode ==
|
||||||
|
"Dark"),
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return MihHomeError(
|
return MihHomeError(
|
||||||
|
|||||||
57
Frontend/lib/mih_services/mih_user_consent_services.dart
Normal file
57
Frontend/lib/mih_services/mih_user_consent_services.dart
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:mzansi_innovation_hub/mih_components/mih_objects/user_consent.dart';
|
||||||
|
import 'package:mzansi_innovation_hub/mih_config/mih_env.dart';
|
||||||
|
import 'package:supertokens_flutter/http.dart' as http;
|
||||||
|
import 'package:supertokens_flutter/supertokens.dart';
|
||||||
|
|
||||||
|
class MihUserConsentServices {
|
||||||
|
Future<UserConsent?> getUserConsentStatus() async {
|
||||||
|
var app_id = await SuperTokens.getUserId();
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse("${AppEnviroment.baseApiUrl}/user-consent/user/$app_id"));
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
Map<String, dynamic> userMap = jsonDecode(response.body);
|
||||||
|
UserConsent userConsent = UserConsent.fromJson(userMap);
|
||||||
|
return userConsent;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> insertUserConsentStatus(
|
||||||
|
String app_id,
|
||||||
|
String latestPrivacyPolicyDate,
|
||||||
|
String latestTermOfServiceDate,
|
||||||
|
) async {
|
||||||
|
UserConsent userConsent = UserConsent(
|
||||||
|
app_id: app_id,
|
||||||
|
privacy_policy_accepted: DateTime.parse(latestPrivacyPolicyDate),
|
||||||
|
terms_of_services_accepted: DateTime.parse(latestTermOfServiceDate),
|
||||||
|
);
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse("${AppEnviroment.baseApiUrl}/user-consent/insert/"),
|
||||||
|
headers: {"Content-Type": "application/json"},
|
||||||
|
body: jsonEncode(userConsent.toJson()),
|
||||||
|
);
|
||||||
|
return response.statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> updateUserConsentStatus(
|
||||||
|
String app_id,
|
||||||
|
String latestPrivacyPolicyDate,
|
||||||
|
String latestTermOfServiceDate,
|
||||||
|
) async {
|
||||||
|
UserConsent userConsent = UserConsent(
|
||||||
|
app_id: app_id,
|
||||||
|
privacy_policy_accepted: DateTime.parse(latestPrivacyPolicyDate),
|
||||||
|
terms_of_services_accepted: DateTime.parse(latestTermOfServiceDate),
|
||||||
|
);
|
||||||
|
final response = await http.put(
|
||||||
|
Uri.parse("${AppEnviroment.baseApiUrl}/user-consent/update"),
|
||||||
|
headers: {"Content-Type": "application/json"},
|
||||||
|
body: jsonEncode(userConsent.toJson()),
|
||||||
|
);
|
||||||
|
return response.statusCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
backend/.DS_Store
vendored
BIN
backend/.DS_Store
vendored
Binary file not shown.
@@ -18,6 +18,7 @@ import routers.access_request as access_request
|
|||||||
import routers.patient_access as patient_access
|
import routers.patient_access as patient_access
|
||||||
import routers.mzansi_wallet as mzansi_wallet
|
import routers.mzansi_wallet as mzansi_wallet
|
||||||
import routers.mzansi_directory as mzansi_directory
|
import routers.mzansi_directory as mzansi_directory
|
||||||
|
import routers.user_consent as user_consent
|
||||||
import routers.icd10_codes as icd10_codes
|
import routers.icd10_codes as icd10_codes
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.middleware import Middleware
|
from fastapi.middleware import Middleware
|
||||||
@@ -94,6 +95,7 @@ app.include_router(business.router)
|
|||||||
app.include_router(notifications.router)
|
app.include_router(notifications.router)
|
||||||
app.include_router(mzansi_wallet.router)
|
app.include_router(mzansi_wallet.router)
|
||||||
app.include_router(mzansi_directory.router)
|
app.include_router(mzansi_directory.router)
|
||||||
|
app.include_router(user_consent.router)
|
||||||
app.include_router(icd10_codes.router)
|
app.include_router(icd10_codes.router)
|
||||||
app.include_router(appointments.router)
|
app.include_router(appointments.router)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from sqlalchemy import DateTime, Column, Integer, String
|
from sqlalchemy import DateTime, Column, Integer, String, text
|
||||||
from sqlalchemy.orm import declarative_base
|
from sqlalchemy.orm import declarative_base
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
||||||
@@ -81,4 +81,20 @@ class BookmarkedBusiness(Base):
|
|||||||
return (
|
return (
|
||||||
f"<BusinessRating(idbookmarked_businesses={self.idbookmarked_businesses}, app_id='{self.app_id}', "
|
f"<BusinessRating(idbookmarked_businesses={self.idbookmarked_businesses}, app_id='{self.app_id}', "
|
||||||
f"business_id='{self.business_id}', created_date='{self.created_date}')>"
|
f"business_id='{self.business_id}', created_date='{self.created_date}')>"
|
||||||
|
)
|
||||||
|
|
||||||
|
class UserConsent(Base):
|
||||||
|
__tablename__ = 'user_consent'
|
||||||
|
__table_args__ = {'schema': 'app_data'}
|
||||||
|
iduser_consent = Column(Integer, primary_key=True)
|
||||||
|
app_id = Column(String(128), nullable=False,server_default=text("''"))
|
||||||
|
privacy_policy_accepted = Column(DateTime, nullable=True)
|
||||||
|
terms_of_services_accepted = Column(DateTime, nullable=True)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return (
|
||||||
|
f"<UserConsent(iduser_consent={self.iduser_consent}, "
|
||||||
|
f"app_id='{self.app_id}', "
|
||||||
|
f"privacy_policy_accepted='{self.privacy_policy_accepted}', "
|
||||||
|
f"terms_of_services_accepted='{self.terms_of_services_accepted}')>"
|
||||||
)
|
)
|
||||||
138
backend/routers/user_consent.py
Normal file
138
backend/routers/user_consent.py
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
from fastapi import APIRouter, HTTPException, status
|
||||||
|
from pydantic import BaseModel
|
||||||
|
#from ..mih_database import dbConnection
|
||||||
|
import mih_database
|
||||||
|
import mih_database.mihDbConnections
|
||||||
|
from mih_database.mihDbObjects import UserConsent
|
||||||
|
from sqlalchemy import desc, or_
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from sqlalchemy.sql import func
|
||||||
|
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
|
||||||
|
#SuperToken Auth from front end
|
||||||
|
from supertokens_python.recipe.session.framework.fastapi import verify_session
|
||||||
|
from supertokens_python.recipe.session import SessionContainer
|
||||||
|
from fastapi import Depends
|
||||||
|
from datetime import datetime
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
class userConsentInsertRequest(BaseModel):
|
||||||
|
app_id: str
|
||||||
|
privacy_policy_accepted: datetime
|
||||||
|
terms_of_services_accepted: datetime
|
||||||
|
|
||||||
|
class userConsentUpdateRequest(BaseModel):
|
||||||
|
app_id: str
|
||||||
|
privacy_policy_accepted: datetime
|
||||||
|
terms_of_services_accepted: datetime
|
||||||
|
|
||||||
|
@router.get("/user-consent/user/{app_id}", tags=["User Consent"])
|
||||||
|
async def get_user_consent(app_id: str, session: SessionContainer = Depends(verify_session())):
|
||||||
|
dbEngine = mih_database.mihDbConnections.dbAllConnect()
|
||||||
|
dbSession = Session(dbEngine)
|
||||||
|
try:
|
||||||
|
queryResults = dbSession.query(UserConsent).\
|
||||||
|
filter(UserConsent.app_id == app_id).\
|
||||||
|
first()
|
||||||
|
if queryResults:
|
||||||
|
return {
|
||||||
|
"idUserConsent": queryResults.iduser_consent,
|
||||||
|
"app_id": queryResults.app_id,
|
||||||
|
"privacy_policy_accepted": queryResults.privacy_policy_accepted,
|
||||||
|
"terms_of_services_accepted": queryResults.terms_of_services_accepted
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User Consent not found")
|
||||||
|
except HTTPException as http_exc:
|
||||||
|
# Re-raise HTTPException directly if it was raised within the try block
|
||||||
|
raise http_exc
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An error occurred during the ORM query: {e}")
|
||||||
|
if dbSession.is_active:
|
||||||
|
dbSession.rollback()
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="Failed to retrieve records due to an internal server error."
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
dbSession.close()
|
||||||
|
|
||||||
|
@router.post("/user-consent/insert/",
|
||||||
|
tags=["User Consent"],
|
||||||
|
status_code=status.HTTP_201_CREATED)
|
||||||
|
async def insert_user_consent(itemRequest: userConsentInsertRequest,
|
||||||
|
session: SessionContainer = Depends(verify_session())):
|
||||||
|
dbEngine = mih_database.mihDbConnections.dbAllConnect()
|
||||||
|
dbSession = Session(dbEngine)
|
||||||
|
try:
|
||||||
|
newUserConsent = UserConsent(
|
||||||
|
app_id = itemRequest.app_id,
|
||||||
|
privacy_policy_accepted = itemRequest.privacy_policy_accepted,
|
||||||
|
terms_of_services_accepted = itemRequest.terms_of_services_accepted,
|
||||||
|
)
|
||||||
|
dbSession.add(newUserConsent)
|
||||||
|
dbSession.commit()
|
||||||
|
dbSession.refresh(newUserConsent)
|
||||||
|
return {"message": "Successfully Created file Record"}
|
||||||
|
except IntegrityError as e:
|
||||||
|
dbSession.rollback()
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT, # 409 Conflict is often suitable for constraint errors
|
||||||
|
detail=f"Data integrity error: The provided data violates a database constraint. Details: {e.orig}"
|
||||||
|
) from e
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
dbSession.rollback()
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail=f"A database error occurred during insertion. Details: {e.orig}"
|
||||||
|
) from e
|
||||||
|
except Exception as e:
|
||||||
|
dbSession.rollback()
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail=f"An unexpected error occurred: {e}"
|
||||||
|
) from e
|
||||||
|
finally:
|
||||||
|
dbSession.close()
|
||||||
|
|
||||||
|
@router.put("/user-consent/update/", tags=["User Consent"])
|
||||||
|
async def update_user_consent(itemRequest: userConsentUpdateRequest,
|
||||||
|
session: SessionContainer = Depends(verify_session())):
|
||||||
|
dbEngine = mih_database.mihDbConnections.dbAllConnect()
|
||||||
|
dbSession = Session(dbEngine)
|
||||||
|
# pp_accepted_dt = datetime.strptime(itemRequest.privacy_policy_accepted, "%Y-%m-%d %H:%M:%S")
|
||||||
|
# tos_accepted_dt = datetime.strptime(itemRequest.terms_of_services_accepted, "%Y-%m-%d %H:%M:%S")
|
||||||
|
try:
|
||||||
|
existing_consent = dbSession.query(UserConsent).filter(UserConsent.app_id == itemRequest.app_id).first()
|
||||||
|
if not existing_consent:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User Consent not found")
|
||||||
|
|
||||||
|
existing_consent.privacy_policy_accepted = itemRequest.privacy_policy_accepted
|
||||||
|
existing_consent.terms_of_services_accepted = itemRequest.terms_of_services_accepted
|
||||||
|
|
||||||
|
dbSession.commit()
|
||||||
|
return {"message": "Successfully Updated User Consent Record"}
|
||||||
|
except HTTPException as http_exc:
|
||||||
|
# Re-raise HTTPException directly if it was raised within the try block
|
||||||
|
raise http_exc
|
||||||
|
except IntegrityError as e:
|
||||||
|
dbSession.rollback()
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
|
detail=f"Data integrity error: The provided data violates a database constraint. Details: {e.orig}"
|
||||||
|
) from e
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
dbSession.rollback()
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail=f"A database error occurred during update. Details: {e.orig}"
|
||||||
|
) from e
|
||||||
|
except Exception as e:
|
||||||
|
dbSession.rollback()
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail=f"An unexpected error occurred: {e}"
|
||||||
|
) from e
|
||||||
|
finally:
|
||||||
|
dbSession.close()
|
||||||
Reference in New Issue
Block a user