From d588de999201879055b4c87c5ab612b0a7cc6b05 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 2 Jul 2025 16:02:56 +0200 Subject: [PATCH 1/4] add auth router --- Frontend/lib/mih_config/mih_routeGenerator.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Frontend/lib/mih_config/mih_routeGenerator.dart b/Frontend/lib/mih_config/mih_routeGenerator.dart index d83f2893..cc20eb9f 100644 --- a/Frontend/lib/mih_config/mih_routeGenerator.dart +++ b/Frontend/lib/mih_config/mih_routeGenerator.dart @@ -13,6 +13,7 @@ import 'package:mzansi_innovation_hub/mih_packages/authentication/forgot_passwor import 'package:mzansi_innovation_hub/mih_packages/authentication/reset_password.dart'; import 'package:mzansi_innovation_hub/mih_packages/calculator/mih_calculator.dart'; import 'package:mzansi_innovation_hub/mih_packages/calendar/mzansi_calendar.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mih_authentication/mih_authentication.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_ai/mzansi_ai.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/profile_business_add.dart'; @@ -38,6 +39,7 @@ class AppRoutes { // Internal static const String authCheck = '/'; + static const String mihAuthentication = '/mih-authentication'; static const String notifications = '/notifications'; static const String forgotPassword = '/forgot-password'; static const String aboutMih = '/about'; @@ -105,6 +107,14 @@ class RouteGenerator { } break; // Use break and fall through to _errorRoute if argument type is wrong + case AppRoutes.mihAuthentication: + // if (args is AuthArguments) { + return MaterialPageRoute( + settings: settings, + builder: (_) => MihAuthentication(), + ); + // } + // break; // Use break and fall through to _errorRoute if argument type is wrong case AppRoutes.notifications: if (args is NotificationArguments) { return MaterialPageRoute( From 2a269e040770c750db3a312fb5ee6266b6cbe3bb Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 2 Jul 2025 16:03:12 +0200 Subject: [PATCH 2/4] use new mih auth package --- Frontend/lib/mih_packages/authentication/auth_check.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frontend/lib/mih_packages/authentication/auth_check.dart b/Frontend/lib/mih_packages/authentication/auth_check.dart index 3510694c..1ba0e1d8 100644 --- a/Frontend/lib/mih_packages/authentication/auth_check.dart +++ b/Frontend/lib/mih_packages/authentication/auth_check.dart @@ -1,10 +1,10 @@ import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_packages/authentication/biometric_check.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mih_authentication/mih_authentication.dart'; import 'package:supertokens_flutter/supertokens.dart'; // import 'package:no_screenshot/no_screenshot.dart'; -import 'signin_or_register.dart'; class AuthCheck extends StatefulWidget { final bool personalSelected; @@ -69,7 +69,7 @@ class _AuthCheckState extends State { firstBoot: widget.firstBoot, ); } else if (snapshot.data == false) { - return const SignInOrRegister(); + return MihAuthentication(); } else { return // const SizedBox(width: 5, height: 5); From b4d8776443ea0e5fc5f45631f37cf52f8ddc90b9 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 2 Jul 2025 16:04:05 +0200 Subject: [PATCH 3/4] new mih auth package --- .../mih_packages/authentication/signin.dart | 2 - .../mih_authentication.dart | 85 +++ .../package_tools/mih_register.dart | 379 ++++++++++++++ .../package_tools/mih_sign_in.dart | 489 ++++++++++++++++++ .../mih_authentication_services.dart | 153 ++++++ .../lib/mih_services/mih_user_services.dart | 87 ++-- 6 files changed, 1159 insertions(+), 36 deletions(-) create mode 100644 Frontend/lib/mih_packages/mih_authentication/mih_authentication.dart create mode 100644 Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart create mode 100644 Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart create mode 100644 Frontend/lib/mih_services/mih_authentication_services.dart diff --git a/Frontend/lib/mih_packages/authentication/signin.dart b/Frontend/lib/mih_packages/authentication/signin.dart index 5d8abf6e..16a2fbdb 100644 --- a/Frontend/lib/mih_packages/authentication/signin.dart +++ b/Frontend/lib/mih_packages/authentication/signin.dart @@ -46,14 +46,12 @@ class _SignInState extends State { //sign user in Future 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"), diff --git a/Frontend/lib/mih_packages/mih_authentication/mih_authentication.dart b/Frontend/lib/mih_packages/mih_authentication/mih_authentication.dart new file mode 100644 index 00000000..1908e703 --- /dev/null +++ b/Frontend/lib/mih_packages/mih_authentication/mih_authentication.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.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_tools.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mih_authentication/package_tools/mih_register.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mih_authentication/package_tools/mih_sign_in.dart'; + +class MihAuthentication extends StatefulWidget { + const MihAuthentication({super.key}); + + @override + State createState() => _MihAuthenticationState(); +} + +class _MihAuthenticationState extends State { + int _selcetedIndex = 0; + + @override + Widget build(BuildContext context) { + return MihPackage( + appActionButton: getAction(), + appTools: getTools(), + appBody: getToolBody(), + selectedbodyIndex: _selcetedIndex, + onIndexChange: (newValue) { + setState(() { + _selcetedIndex = newValue; + }); + }, + ); + } + + List getToolBody() { + List toolBodies = [ + MihSignIn( + onNewUserButtonTap: () { + setState(() { + _selcetedIndex = 1; + }); + }, + ), + MihRegister(onExistingUserButtonTap: () { + setState(() { + _selcetedIndex = 0; + }); + }) + ]; + return toolBodies; + } + + MihPackageTools getTools() { + Map temp = {}; + temp[const Icon(Icons.perm_identity)] = () { + setState(() { + _selcetedIndex = 0; + }); + }; + temp[const Icon(Icons.create)] = () { + setState(() { + _selcetedIndex = 1; + }); + }; + return MihPackageTools( + tools: temp, + selcetedIndex: _selcetedIndex, + ); + } + + MihPackageAction getAction() { + return MihPackageAction( + icon: Padding( + padding: const EdgeInsets.only(left: 10.0), + child: const Icon(MihIcons.mihLogo), + ), + iconSize: 45, + onTap: () { + Navigator.of(context).pushNamed( + '/about', + arguments: 0, + ); + }, + ); + } +} diff --git a/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart new file mode 100644 index 00000000..76a6ebdc --- /dev/null +++ b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_register.dart @@ -0,0 +1,379 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:mzansi_innovation_hub/main.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_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:supertokens_flutter/http.dart' as http; +import 'package:supertokens_flutter/supertokens.dart'; + +class MihRegister extends StatefulWidget { + final void Function()? onExistingUserButtonTap; + const MihRegister({ + super.key, + required this.onExistingUserButtonTap, + }); + + @override + State createState() => _MihRegisterState(); +} + +class _MihRegisterState extends State { + final emailController = TextEditingController(); + final passwordController = TextEditingController(); + final confirmPasswordController = TextEditingController(); + final FocusNode _focusNode = FocusNode(); + final _formKey = GlobalKey(); + final baseAPI = AppEnviroment.baseApiUrl; + + Future addUserAPICall(String email, String uid) async { + //await getOfficeIdByUser(docOfficeIdApiUrl + widget.userEmail); + //print(futureDocOfficeId.toString()); + await MihUserServices().createUser( + email, + uid, + context, + ); + // var response = await http.post( + // Uri.parse("$baseAPI/user/insert/"), + // headers: { + // "Content-Type": "application/json; charset=UTF-8" + // }, + // body: jsonEncode({ + // "email": email, + // "app_id": uid, + // }), + // ); + // if (response.statusCode == 201) { + // Navigator.of(context).pushNamedAndRemoveUntil( + // '/', + // (route) => false, + // arguments: AuthArguments( + // true, + // true, + // ), + // ); + // // signUpSuccess(); + // // setState(() { + // // successfulSignUp = true; + // // }); + // } else { + // internetConnectionPopUp(); + // } + } + + Future 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"]) { + Navigator.of(context).pop(); + 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 Exception catch (error) { + Navigator.of(context).pop(); + loginError(error.toString()); + emailController.clear(); + passwordController.clear(); + confirmPasswordController.clear(); + } + } + } + + void submitFormInput() async { + await signUserUp(); + } + + bool validEmail() { + String text = emailController.text; + var regex = RegExp(r'^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$'); + return regex.hasMatch(text); + } + + void loginError(error) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text(error), + ); + }, + ); + } + + void emailError() { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Invalid Email"); + }, + ); + } + + 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 internetConnectionPopUp() { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Internet Connection"); + }, + ); + } + + void passwordReqError() { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Password Requirements"); + }, + ); + } + + @override + Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + return MihPackageToolBody( + borderOn: false, + bodyItem: getBody(screenWidth), + ); + } + + Widget getBody(double width) { + return KeyboardListener( + focusNode: _focusNode, + autofocus: true, + onKeyEvent: (event) async { + if (event is KeyDownEvent && + event.logicalKey == LogicalKeyboardKey.enter) { + if (_formKey.currentState!.validate()) { + submitFormInput(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + } + }, + child: MihSingleChildScroll( + child: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + 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( + 'Create an Account', + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + ), + ), + //spacer + // const SizedBox(height: 20), + MihForm( + formKey: _formKey, + formFields: [ + //email input + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: emailController, + multiLineInput: false, + requiredText: true, + hintText: "Email", + autofillHints: const [AutofillHints.email], + validator: (value) { + return MihValidationServices().validateEmail(value); + }, + ), + //spacer + const SizedBox(height: 10), + //password input + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: passwordController, + multiLineInput: false, + requiredText: true, + hintText: "Password", + passwordMode: true, + autofillHints: const [AutofillHints.password], + validator: (value) { + return MihValidationServices().validatePassword(value); + }, + ), + //spacer + const SizedBox(height: 10), + MihTextFormField( + fillColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: confirmPasswordController, + multiLineInput: false, + requiredText: true, + hintText: "Confirm Password", + passwordMode: true, + autofillHints: const [AutofillHints.password], + validator: (value) { + return MihValidationServices().validatePassword(value); + }, + ), + //spacer + const SizedBox(height: 20), + // sign up button + Center( + child: Wrap( + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitFormInput(); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .successColor(), + width: 300, + child: Text( + "Create New Account", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + MihButton( + onPressed: widget.onExistingUserButtonTap, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 300, + child: Text( + "I have an account", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ), + + //here + ], + ) + ], + ), + ), + ), + ); + } +} diff --git a/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart new file mode 100644 index 00000000..473f49ec --- /dev/null +++ b/Frontend/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart @@ -0,0 +1,489 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_tile.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.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_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_authentication_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_install_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; + +class MihSignIn extends StatefulWidget { + final void Function()? onNewUserButtonTap; + const MihSignIn({ + super.key, + required this.onNewUserButtonTap, + }); + + @override + State createState() => _MihSignInState(); +} + +class _MihSignInState extends State { + final emailController = TextEditingController(); + final passwordController = TextEditingController(); + final FocusNode _focusNode = FocusNode(); + final _formKey = GlobalKey(); + bool successfulSignIn = false; + bool showProfiles = false; + final baseAPI = AppEnviroment.baseApiUrl; + late List sandboxProfileList = []; + + //sign user in + Future signUserIn() async { + try { + successfulSignIn = await MihAuthenticationServices().signUserIn( + emailController.text, + passwordController.text, + context, + ); + if (!successfulSignIn) { + loginError(); + passwordController.clear(); + } + } on Exception { + Navigator.of(context).pop(); + loginError(); + passwordController.clear(); + } + } + + void submitSignInForm() async { + await signUserIn(); + if (successfulSignIn) { + Navigator.of(context).pushNamedAndRemoveUntil( + '/', + (route) => false, + arguments: AuthArguments( + true, + true, + ), + ); + } + } + + void setSandboxProfiles(List tileList) { + tileList.add(MIHTile( + onTap: () { + setState(() { + emailController.text = "testpatient@mzansi-innovation-hub.co.za"; + passwordController.text = "Testprofile@1234"; + }); + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + tileName: "Patient", + tileIcon: Icon( + Icons.perm_identity_rounded, + color: getSec(), + size: 200, + ), + p: getPrim(), + s: getSec(), + )); + tileList.add(MIHTile( + onTap: () { + setState(() { + emailController.text = "testdoctor@mzansi-innovation-hub.co.za"; + passwordController.text = "Testprofile@1234"; + }); + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + tileName: "Doctor", + tileIcon: Icon( + Icons.medical_services, + color: getSec(), + size: 200, + ), + p: getPrim(), + s: getSec(), + )); + //if (AppEnviroment.getEnv() == "Dev") { + tileList.add(MIHTile( + onTap: () { + setState(() { + emailController.text = "test-business@mzansi-innovation-hub.co.za"; + passwordController.text = "Testprofile@1234"; + }); + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + tileName: "Business", + tileIcon: Icon( + Icons.business, + color: getSec(), + size: 200, + ), + p: getPrim(), + s: getSec(), + )); + tileList.add(MIHTile( + onTap: () { + setState(() { + emailController.text = "test@mzansi-innovation-hub.co.za"; + passwordController.text = "Testprofile@1234"; + }); + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + tileName: "Test", + tileIcon: Icon( + Icons.warning_amber_rounded, + color: getSec(), + size: 200, + ), + p: getPrim(), + s: getSec(), + )); + //} + } + + Color getPrim() { + return MzanziInnovationHub.of(context)!.theme.secondaryColor(); + } + + Color getSec() { + return MzanziInnovationHub.of(context)!.theme.primaryColor(); + } + + void loginError() { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Invalid Credentials"); + }, + ); + } + + @override + void initState() { + super.initState(); + setState(() { + setSandboxProfiles(sandboxProfileList); + }); + } + + @override + Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + return MihPackageToolBody( + borderOn: false, + bodyItem: getBody(screenWidth), + ); + } + + Widget getBody(double width) { + return KeyboardListener( + focusNode: _focusNode, + autofocus: true, + onKeyEvent: (event) async { + if (event is KeyDownEvent && + event.logicalKey == LogicalKeyboardKey.enter) { + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + } + }, + child: MihSingleChildScroll( + child: Padding( + padding: + MzanziInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: AutofillGroup( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Visibility( + visible: MzanziInnovationHub.of(context)! + .theme + .getPlatform() == + "Web", + child: Padding( + padding: const EdgeInsets.all(10.0), + child: MihButton( + onPressed: () { + MihInstallServices().installMihTrigger(context); + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .successColor(), + width: 150, + child: Text( + "Install MIH", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ), + ], + ), + //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: 10), + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: emailController, + multiLineInput: false, + requiredText: true, + hintText: "Email", + autofillHints: const [AutofillHints.email], + validator: (value) { + return MihValidationServices().validateEmail(value); + }, + ), + //spacer + const SizedBox(height: 10), + //password input + MihTextFormField( + fillColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + inputColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + controller: passwordController, + multiLineInput: false, + requiredText: true, + hintText: "Password", + passwordMode: true, + autofillHints: const [AutofillHints.password], + validator: (value) { + return MihValidationServices().validatePassword(value); + }, + ), + const SizedBox(height: 10), + 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: 20), + // sign in button + Center( + child: Wrap( + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitSignInForm(); + } else { + MihAlertServices() + .formNotFilledCompletely(context); + } + }, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .successColor(), + width: 300, + child: Text( + "Sign In", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + MihButton( + onPressed: widget.onNewUserButtonTap, + buttonColor: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + width: 300, + child: Text( + "Create New Account", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ), + + //spacer + const SizedBox(height: 35), + Center( + child: SizedBox( + width: width, + //height: 100.0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Flexible( + flex: 1, + child: Padding( + padding: EdgeInsets.only(right: 10.0), + child: Divider(), + ), + ), + Flexible( + flex: 1, + child: GestureDetector( + child: Text( + 'Use Sandox Profile', + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor()), + ), + onTap: () { + setState(() { + showProfiles = !showProfiles; + }); + }, + ), + ), + const Flexible( + flex: 1, + child: Padding( + padding: EdgeInsets.only(left: 10.0), + child: Divider(), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 10), + Center( + child: Visibility( + visible: showProfiles, + child: SizedBox( + width: 500, + child: Column( + //mainAxisSize: MainAxisSize.max, + children: [ + GridView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: sandboxProfileList.length, + gridDelegate: + const SliverGridDelegateWithMaxCrossAxisExtent( + mainAxisSpacing: 10, + maxCrossAxisExtent: 100), + itemBuilder: (context, index) { + return sandboxProfileList[index]; + }, + ), + // 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 + .errorColor(), + fontSize: 15.0, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/Frontend/lib/mih_services/mih_authentication_services.dart b/Frontend/lib/mih_services/mih_authentication_services.dart new file mode 100644 index 00000000..acee93a2 --- /dev/null +++ b/Frontend/lib/mih_services/mih_authentication_services.dart @@ -0,0 +1,153 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +// import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; +import 'package:supertokens_flutter/http.dart' as http; +// import 'package:supertokens_flutter/supertokens.dart'; + +class MihAuthenticationServices { + final baseAPI = AppEnviroment.baseApiUrl; + + // Future signUserUp( + // TextEditingController emailController, + // TextEditingController passwordController, + // TextEditingController confirmPasswordController, + // BuildContext context, + // ) async { + // showDialog( + // context: context, + // builder: (context) { + // return const Mihloadingcircle(); + // }, + // ); + // try { + // Uri uri = Uri.parse( + // "$baseAPI/auth/emailpassword/email/exists?email=${emailController.text}"); + // var response = await http.get(uri); + // if (response.statusCode == 200) { + // var userExists = jsonDecode(response.body); + // if (userExists["exists"]) { + // Navigator.of(context).pop(); + // signUpError(context); + // } 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"); + // await MihUserServices() + // .createUser(emailController.text, uid, context); + // // addUserAPICall(emailController.text, uid); + // Navigator.of(context).pop(); + // //print("Here1"); + // } else if (userCreated["status"] == "FIELD_ERROR") { + // Navigator.of(context).pop(); + // passwordReqError(context); + // } else { + // Navigator.of(context).pop(); + // internetConnectionPopUp(context); + // } + // } + // } + // } + // } on Exception catch (error) { + // Navigator.of(context).pop(); + // loginError(error.toString(), context); + // emailController.clear(); + // passwordController.clear(); + // confirmPasswordController.clear(); + // } + // } + + Future signUserIn( + String email, + String password, + BuildContext context, + ) async { + //var _backgroundColor = Colors.transparent; + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle(); + }, + ); + var response = await http.post( + Uri.parse("$baseAPI/auth/signin"), + body: + '{"formFields": [{"id": "email","value": "$email"}, {"id": "password","value": "$password"}]}', + headers: { + 'Content-type': 'application/json', + 'Accept': 'application/json', + "Authorization": "leatucczyixqwkqqdrhayiwzeofkltds" + }, + ); + if (response.statusCode == 200) { + var userSignedin = jsonDecode(response.body); + if (userSignedin["status"] == "OK") { + Navigator.of(context).pop(); + return true; + } else { + Navigator.of(context).pop(); + return false; + } + } else { + return false; + } + } + + void internetConnectionPopUp(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Internet Connection"); + }, + ); + } + + void loginError(String error, BuildContext context) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text(error), + ); + }, + ); + } + + void passwordReqError(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Password Requirements"); + }, + ); + } + + void signUpError(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "User Exists"); + }, + ); + } +} diff --git a/Frontend/lib/mih_services/mih_user_services.dart b/Frontend/lib/mih_services/mih_user_services.dart index a0c7b8d6..1432da4d 100644 --- a/Frontend/lib/mih_services/mih_user_services.dart +++ b/Frontend/lib/mih_services/mih_user_services.dart @@ -30,6 +30,39 @@ class MihUserServices { } } + Future createUser( + String email, + String app_id, + BuildContext context, + ) async { + var response = await http.post( + Uri.parse("$baseAPI/user/insert/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "email": email, + "app_id": app_id, + }), + ); + if (response.statusCode == 201) { + Navigator.of(context).pushNamedAndRemoveUntil( + '/', + (route) => false, + arguments: AuthArguments( + true, + true, + ), + ); + // signUpSuccess(); + // setState(() { + // successfulSignUp = true; + // }); + } else { + internetConnectionPopUp(context); + } + } + Future getUserDetails( String app_id, BuildContext context, @@ -60,33 +93,32 @@ class MihUserServices { BuildContext context, ) async { var fileName = profilePicture.replaceAll(RegExp(r' '), '-'); - var filePath = - "${signedInUser.app_id}/profile_files/$fileName"; + var filePath = "${signedInUser.app_id}/profile_files/$fileName"; String profileType; if (isBusinessUser) { profileType = "business"; } else { profileType = "personal"; } - var response = await http.put( - Uri.parse("${AppEnviroment.baseApiUrl}/user/update/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({ - "idusers": signedInUser.idUser, - "username": username, - "fnam": firstName, - "lname": lastName, - "type": profileType, - "pro_pic_path": filePath, - }), - ); - if (response.statusCode == 200) { - return response.statusCode; - } else { - return response.statusCode; - } + var response = await http.put( + Uri.parse("${AppEnviroment.baseApiUrl}/user/update/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "idusers": signedInUser.idUser, + "username": username, + "fnam": firstName, + "lname": lastName, + "type": profileType, + "pro_pic_path": filePath, + }), + ); + if (response.statusCode == 200) { + return response.statusCode; + } else { + return response.statusCode; + } } static Future deleteAccount( @@ -128,19 +160,6 @@ class MihUserServices { } } - // Future signOut() async { - // await SuperTokens.signOut(completionHandler: (error) { - // print(error); - // }); - // if (await SuperTokens.doesSessionExist() == false) { - // Navigator.of(context).pop(); - // Navigator.of(context).popAndPushNamed( - // '/', - // arguments: AuthArguments(true, false), - // ); - // } - // } - //================== POP UPS ========================================================================== static void internetConnectionPopUp(BuildContext context) { From 2e636e7ec99d134fa8317b9d15dd802763f6718f Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 2 Jul 2025 16:04:56 +0200 Subject: [PATCH 4/4] bring back gpu ollama --- docker-compose.yml | 56 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2be023d5..f8f12daa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -169,34 +169,34 @@ services: networks: - MIH-network # === Added section for NVIDIA GPU acceleration === - # runtime: nvidia - # deploy: - # resources: - # reservations: - # devices: - # - driver: nvidia - # count: all # or specify a number of GPUs - # capabilities: [ gpu ] - #============== Firebaase ==================================================================== - # firebase: - # container_name: MIH-firebase-emulator - # build: - # context: ./Firebase-emulator - # environment: - # DATA_DIRECTORY: "firebase/data" - # FIREBASE_PROJECT: "mzansi-innovation-hub" - # ports: - # - 8082:8080 # FIRESTORE_PORT - # - 5005:5005 # FIRESTORE_WS_PORT - # - 4000:4000 # UI_PORT - # - 9099:9099 # AUTH_PORT - # - 5000:6001 # Hosting - # volumes: - # - ./Firebase-emulator:/srv/firebase:rw - # # - ./cache:/root/.cache/:rw - # # - ~/.config/:/root/.config - # - ./Firebase-emulator/firebase/data:/srv/firebase/data:rw - #============== Named Volumes ==================================================================== + runtime: nvidia + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all # or specify a number of GPUs + capabilities: [ gpu ] +#============== Firebaase ==================================================================== +# firebase: +# container_name: MIH-firebase-emulator +# build: +# context: ./Firebase-emulator +# environment: +# DATA_DIRECTORY: "firebase/data" +# FIREBASE_PROJECT: "mzansi-innovation-hub" +# ports: +# - 8082:8080 # FIRESTORE_PORT +# - 5005:5005 # FIRESTORE_WS_PORT +# - 4000:4000 # UI_PORT +# - 9099:9099 # AUTH_PORT +# - 5000:6001 # Hosting +# volumes: +# - ./Firebase-emulator:/srv/firebase:rw +# # - ./cache:/root/.cache/:rw +# # - ~/.config/:/root/.config +# - ./Firebase-emulator/firebase/data:/srv/firebase/data:rw +#============== Named Volumes ==================================================================== volumes: certbotConf: certbotChall: