Merge pull request #250 from yaso-meth/NEW--Deep-Linking

NEW--Deep-Linking
This commit is contained in:
yaso-meth
2025-09-12 13:42:28 +02:00
committed by GitHub
197 changed files with 5556 additions and 4098 deletions

View File

@@ -2,6 +2,7 @@
xmlns:tools="http://schemas.android.com/tools">
<!-- <uses-permission android:name="com.google.android.gms.permission.AD_ID"
tools:node="merge"/> -->
<uses-permission android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -42,6 +43,18 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data
android:name="flutter-deeplink"
android:value="true"
/>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="app.mzansi-innovation-hub.co.za" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 69 B

View File

@@ -1,3 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
extensions:

View File

@@ -40,7 +40,7 @@ PODS:
- fl_downloader (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_native_splash (0.0.1):
- flutter_native_splash (2.4.3):
- Flutter
- flutter_tts (0.0.1):
- Flutter
@@ -65,6 +65,8 @@ PODS:
- FlutterMacOS
- printing (1.0.0):
- Flutter
- screen_brightness_ios (0.1.0):
- Flutter
- SDWebImage (5.20.0):
- SDWebImage/Core (= 5.20.0)
- SDWebImage/Core (5.20.0)
@@ -73,6 +75,9 @@ PODS:
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
- SwiftyGif (5.4.5)
- syncfusion_flutter_pdfviewer (0.0.1):
- Flutter
@@ -96,8 +101,10 @@ DEPENDENCIES:
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- printing (from `.symlinks/plugins/printing/ios`)
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- syncfusion_flutter_pdfviewer (from `.symlinks/plugins/syncfusion_flutter_pdfviewer/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
@@ -138,10 +145,14 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
printing:
:path: ".symlinks/plugins/printing/ios"
screen_brightness_ios:
:path: ".symlinks/plugins/screen_brightness_ios/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite_darwin:
:path: ".symlinks/plugins/sqflite_darwin/darwin"
syncfusion_flutter_pdfviewer:
:path: ".symlinks/plugins/syncfusion_flutter_pdfviewer/ios"
url_launcher_ios:
@@ -157,7 +168,7 @@ SPEC CHECKSUMS:
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
fl_downloader: dc99aa8dd303f862cccb830087f37acc9b0156ee
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_native_splash: 35ddbc7228eafcb3969dcc5f1fbbe27c1145a4f0
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
flutter_tts: b88dbc8655d3dc961bc4a796e4e16a4cc1795833
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
Google-Mobile-Ads-SDK: 1dfb0c3cb46c7e2b00b0f4de74a1e06d9ea25d67
@@ -167,9 +178,11 @@ SPEC CHECKSUMS:
mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
printing: 54ff03f28fe9ba3aa93358afb80a8595a071dd07
screen_brightness_ios: 9953fd7da5bd480f1a93990daeec2eb42d4f3b52
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
syncfusion_flutter_pdfviewer: 90dc48305d2e33d4aa20681d1e98ddeda891bc14
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d

View File

@@ -44,6 +44,7 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2059B8BD2E7405B800139A50 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
209959071B4259A271891D6D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
244BDC62FF4364AA78470B4E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
277EDD110F2042FAAC4E5333 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -152,6 +153,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
2059B8BD2E7405B800139A50 /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
@@ -485,6 +487,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = B88N73P46W;
ENABLE_BITCODE = NO;
@@ -667,6 +670,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = B88N73P46W;
ENABLE_BITCODE = NO;
@@ -693,6 +697,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = B88N73P46W;
ENABLE_BITCODE = NO;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -41,7 +41,7 @@
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="512" height="512"/>
<image name="LaunchImage" width="1024" height="1024"/>
<image name="LaunchBackground" width="1" height="1"/>
<image name="BrandingImage" width="1" height="1"/>
</resources>

View File

@@ -1,77 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-4781880856775334~6935644635</string>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>MIH</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>mzansi_innovation_hub</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>sms</string>
<string>tel</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan QR codes</string>
<key>NSFaceIDUsageDescription</key>
<string>Why is my app authenticating using face id?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs to access your photo library to select images.</string>
<key>NSDownloadsFolderUsageDescription</key>
<string>This app needs to access your downloads folder to select files from there.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UIFileSharingEnabled</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<false/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
<dict>
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-4781880856775334~6935644635</string>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>MIH</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>mzansi_innovation_hub</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>sms</string>
<string>tel</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan QR codes</string>
<key>NSFaceIDUsageDescription</key>
<string>Why is my app authenticating using face id?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs to access your photo library to select images.</string>
<key>NSDownloadsFolderUsageDescription</key>
<string>This app needs to access your downloads folder to select files from there.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UIFileSharingEnabled</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<false/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:app.mzansi-innovation-hub.co.za</string>
</array>
</dict>
</plist>

View File

@@ -1,12 +1,14 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'mih_config/mih_env.dart';
import 'mih_config/mih_routeGenerator.dart';
import 'mih_config/mih_theme.dart';
class MzansiInnovationHub extends StatefulWidget {
final GoRouter router;
const MzansiInnovationHub({
super.key,
required this.router,
});
@override
@@ -53,18 +55,9 @@ class _MzansiInnovationHubState extends State<MzansiInnovationHub> {
@override
void initState() {
theme = MihTheme();
// var systemTheme =
// SchedulerBinding.instance.platformDispatcher.platformBrightness;
// bool isDarkMode = systemTheme == Brightness.dark;
// if (isDarkMode) {
// theme.mode = "Dark";
// } else {
// theme.mode = "Light";
// }
super.initState();
theme.mode = "Dark";
theme.platform = Theme.of(context).platform;
//doInit();
}
@override
@@ -72,14 +65,13 @@ class _MzansiInnovationHubState extends State<MzansiInnovationHub> {
double width = MediaQuery.sizeOf(context).width;
theme.setScreenType(width);
precacheImage(theme.loadingImage(), context);
return MaterialApp(
return MaterialApp.router(
title: getTitle(),
themeMode: ThemeMode.dark,
theme: theme.getThemeData(),
darkTheme: theme.getThemeData(),
debugShowCheckedModeBanner: false,
initialRoute: '/',
onGenerateRoute: RouteGenerator.generateRoute,
routerConfig: widget.router,
);
}
}
}

View File

@@ -3,8 +3,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:flutter_web_plugins/url_strategy.dart'
if (dart.library.html) 'package:flutter_web_plugins/url_strategy.dart';
import 'package:go_router/go_router.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_go_router.dart';
import 'package:pwa_install/pwa_install.dart';
import 'mih_config/mih_env.dart';
import 'package:supertokens_flutter/supertokens.dart';
@@ -25,6 +27,7 @@ void main() async {
PWAInstall().setup(installCallback: () {
debugPrint('APP INSTALLED!');
});
final GoRouter appRouter = MihGoRouter().mihRouter;
FlutterNativeSplash.remove();
runApp(const MzansiInnovationHub());
runApp(MzansiInnovationHub(router: appRouter,));
}

View File

@@ -3,8 +3,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:flutter_web_plugins/url_strategy.dart'
if (dart.library.html) 'package:flutter_web_plugins/url_strategy.dart';
import 'package:go_router/go_router.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_go_router.dart';
import 'package:pwa_install/pwa_install.dart';
import 'mih_config/mih_env.dart';
import 'package:supertokens_flutter/supertokens.dart';
@@ -25,6 +27,7 @@ void main() async {
PWAInstall().setup(installCallback: () {
debugPrint('APP INSTALLED!');
});
final GoRouter appRouter = MihGoRouter().mihRouter;
FlutterNativeSplash.remove();
runApp(const MzansiInnovationHub());
runApp(MzansiInnovationHub(router: appRouter,));
}

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.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';
@@ -32,11 +33,16 @@ class _PackageTestState extends State<PackageTest> {
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).popAndPushNamed(
'/',
arguments: AuthArguments(true, false),
context.goNamed(
'mihHome',
extra: true,
);
FocusScope.of(context).unfocus();
// Navigator.of(context).pop();
// Navigator.of(context).popAndPushNamed(
// '/',
// arguments: AuthArguments(true, false),
// );
},
);
}
@@ -124,7 +130,7 @@ class _PackageTestState extends State<PackageTest> {
List<Widget> toolBodies = [
PackageToolOne(
user: widget.arguments.user,
business: widget.arguments.business!,
business: widget.arguments.business,
),
const PackageToolTwo(),
];

View File

@@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
class TestPackageTile extends StatefulWidget {
final AppUser signedInUser;
final Business? business;
final double packageSize;
const TestPackageTile({
super.key,
required this.signedInUser,
required this.business,
required this.packageSize,
});
@override
State<TestPackageTile> createState() => _TestPackageTileState();
}
class _TestPackageTileState extends State<TestPackageTile> {
@override
Widget build(BuildContext context) {
return MihPackageTile(
onTap: () {
context.goNamed(
'testPackage',
extra: TestArguments(
widget.signedInUser,
widget.business,
),
);
// Navigator.of(context).pushNamed(
// '/package-dev',
// arguments: TestArguments(
// widget.signedInUser,
// widget.business,
// ),
// );
},
appName: "Test",
appIcon: Icon(
Icons.warning_amber_rounded,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
iconSize: widget.packageSize,
primaryColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
secondaryColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
}
}

View File

@@ -38,7 +38,7 @@ import 'package:redacted/redacted.dart';
class PackageToolOne extends StatefulWidget {
final AppUser user;
final Business business;
final Business? business;
const PackageToolOne({
super.key,
required this.user,
@@ -393,17 +393,19 @@ class _PackageToolOneState extends State<PackageToolOne> {
.replaceAll("Latitude: ", "")
.replaceAll("Longitude: ", "");
print("My Location is this: $myLocation");
return MihBusinessProfilePreview(
business: widget.business,
myLocation: myLocation,
);
return widget.business != null
? MihBusinessProfilePreview(
business: widget.business!,
myLocation: myLocation,
)
: Text("NoBusiness Data");
}
}),
const SizedBox(height: 10),
Text("This text should be redacted").redacted(
context: context,
redact: true,
),
// const SizedBox(height: 10),
// Text("This text should be redacted").redacted(
// context: context,
// redact: true,
// ),
MihBusinessCard(
business: Business(
"business_id",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 MiB

View File

@@ -4,6 +4,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
class MihCircleAvatar extends StatefulWidget {
final ImageProvider<Object>? imageFile;
@@ -54,7 +55,6 @@ class _MihCircleAvatarState extends State<MihCircleAvatar> {
@override
void initState() {
super.initState();
print("Avatar started");
setState(() {
imagePreview = getAvatar();
});
@@ -72,21 +72,20 @@ class _MihCircleAvatarState extends State<MihCircleAvatar> {
children: [
Visibility(
visible: imagePreview != null,
child: CircleAvatar(
radius: widget.width / 2.2,
backgroundColor: widget.backgroundColor,
backgroundImage: imagePreview,
child: Positioned(
child: CircleAvatar(
radius: widget.width / 2.2,
backgroundColor: widget.backgroundColor,
backgroundImage: imagePreview,
),
),
),
Visibility(
visible: imagePreview != null,
child: FittedBox(
fit: BoxFit.fill,
child: Icon(
size: widget.width,
MihIcons.mihRing,
color: widget.frameColor,
),
child: Icon(
size: widget.width,
MihIcons.mihRing,
color: widget.frameColor,
),
),
Visibility(
@@ -103,6 +102,12 @@ class _MihCircleAvatarState extends State<MihCircleAvatar> {
bottom: 0,
right: 0,
child: IconButton.filled(
style: ButtonStyle(
backgroundColor: WidgetStateProperty.all<Color>(
MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
onPressed: () async {
try {
FilePickerResult? result =
@@ -154,7 +159,9 @@ class _MihCircleAvatarState extends State<MihCircleAvatar> {
print("Error: $e");
}
},
icon: const Icon(Icons.edit),
icon: Icon(
Icons.edit,
),
),
),
),

View File

@@ -76,11 +76,11 @@ class _MihImageDisplayState extends State<MihImageDisplay> {
Visibility(
visible: widget.editable,
child: Positioned(
bottom: 0,
right: 0,
bottom: 5,
right: 5,
child: IconButton.filled(
style: IconButton.styleFrom(
backgroundColor: MihColors.getSecondaryColor(
backgroundColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
color: MihColors.getPrimaryColor(

View File

@@ -1,4 +1,8 @@
import 'package:flutter/services.dart';
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/mih_components/mih_package_components/mih_scack_bar.dart';
import 'package:mzansi_innovation_hub/mih_packages/mih_home/components/mih_app_drawer.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart';
import 'package:flutter/material.dart';
@@ -31,6 +35,7 @@ class _MihPackageState extends State<MihPackage>
with SingleTickerProviderStateMixin {
late PageController _pageController;
late AnimationController _animationController;
DateTime? lastPressedAt;
void unfocusAll() {
FocusScope.of(context).unfocus();
@@ -113,69 +118,96 @@ class _MihPackageState extends State<MihPackage>
Size screenSize = MediaQuery.of(context).size;
return GestureDetector(
onTap: unfocusAll,
child: Scaffold(
drawer: widget.actionDrawer,
body: SafeArea(
bottom: false,
minimum: EdgeInsets.only(bottom: 0),
child: Container(
width: screenSize.width,
height: screenSize.height,
//color: Colors.black,
padding: const EdgeInsets.only(top: 5),
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
widget.appActionButton,
const SizedBox(
width: 10,
),
Expanded(
child: Container(
// alignment: Alignment.center,
// alignment: Alignment.centerRight,
alignment: Alignment.centerLeft,
// color: Colors.black,
child: FittedBox(
child: Text(
widget.appToolTitles != null
? widget
.appToolTitles![widget.selectedbodyIndex]
: "",
style: const TextStyle(
fontSize: 23,
fontWeight: FontWeight.w600,
child: PopScope(
canPop: false,
onPopInvokedWithResult: (bool didPop, Object? result) {
if (GoRouterState.of(context).name == 'mihHome' ||
GoRouterState.of(context).name == 'mihAuthentication') {
if (lastPressedAt == null ||
DateTime.now().difference(lastPressedAt!) >
const Duration(seconds: 2)) {
// First press: show a message and update the timestamp.
lastPressedAt = DateTime.now();
ScaffoldMessenger.of(context).showSnackBar(
MihSnackBar(
child: Text("Press back again to exit"),
),
);
} else {
// Second press within 2 seconds: exit the app.
KenLogger.warning('Exiting app...'); // Your custom logger
SystemChannels.platform.invokeMethod('SystemNavigator.pop');
}
} else {
context.goNamed(
'mihHome',
extra: true,
);
}
},
child: Scaffold(
drawer: widget.actionDrawer,
body: SafeArea(
bottom: false,
minimum: EdgeInsets.only(bottom: 0),
child: Container(
width: screenSize.width,
height: screenSize.height,
//color: Colors.black,
padding: const EdgeInsets.only(top: 5),
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
widget.appActionButton,
const SizedBox(
width: 10,
),
Expanded(
child: Container(
// alignment: Alignment.center,
// alignment: Alignment.centerRight,
alignment: Alignment.centerLeft,
// color: Colors.black,
child: FittedBox(
child: Text(
widget.appToolTitles != null
? widget
.appToolTitles![widget.selectedbodyIndex]
: "",
style: const TextStyle(
fontSize: 23,
fontWeight: FontWeight.w600,
),
),
),
),
),
),
const SizedBox(
width: 5,
),
widget.appTools,
],
),
const SizedBox(height: 5),
Expanded(
child: PageView.builder(
controller: _pageController,
itemCount: widget.appBody.length,
itemBuilder: (context, index) {
return widget.appBody[index];
},
onPageChanged: (index) {
setState(() {
widget.selectedbodyIndex = index;
widget.onIndexChange(widget.selectedbodyIndex);
});
},
const SizedBox(width: 5),
widget.appTools,
const SizedBox(width: 5),
],
),
),
],
const SizedBox(height: 5),
Expanded(
child: PageView.builder(
controller: _pageController,
itemCount: widget.appBody.length,
itemBuilder: (context, index) {
return widget.appBody[index];
},
onPageChanged: (index) {
setState(() {
widget.selectedbodyIndex = index;
widget.onIndexChange(widget.selectedbodyIndex);
});
},
),
),
],
),
),
),
),

View File

@@ -1,4 +1,9 @@
import 'package:app_settings/app_settings.dart';
import 'package:flutter/foundation.dart';
import 'package:local_auth/local_auth.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_package_alert.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_yt_video_player.dart';
import 'package:flutter/material.dart';
@@ -12,6 +17,7 @@ class MihPackageTile extends StatefulWidget {
final double iconSize;
final Color primaryColor;
final Color secondaryColor;
final bool? authenticateUser;
const MihPackageTile({
super.key,
required this.onTap,
@@ -21,6 +27,7 @@ class MihPackageTile extends StatefulWidget {
required this.iconSize,
required this.primaryColor,
required this.secondaryColor,
this.authenticateUser,
});
@override
@@ -28,6 +35,8 @@ class MihPackageTile extends StatefulWidget {
}
class _MihPackageTileState extends State<MihPackageTile> {
final LocalAuthentication _auth = LocalAuthentication();
void displayHint() {
if (widget.ytVideoID != null) {
showDialog(
@@ -49,6 +58,128 @@ class _MihPackageTileState extends State<MihPackageTile> {
}
}
Future<bool> isUserAuthenticated() async {
final bool canAuthWithBio = await _auth.canCheckBiometrics;
final bool canAuthenticate =
canAuthWithBio || await _auth.isDeviceSupported();
print("Auth Available: $canAuthenticate");
if (canAuthenticate) {
try {
final bool didBioAuth = await _auth.authenticate(
localizedReason: "Authenticate to access ${widget.appName}",
options: const AuthenticationOptions(
biometricOnly: false,
),
);
if (didBioAuth) {
return true;
} else {
authErrorPopUp();
}
// print("Authenticated: $didBioAuth");
} catch (error) {
print("Auth Error: $error");
authErrorPopUp();
}
} else {
print("Auth Error: No Biometrics Available");
authErrorPopUp();
}
return false;
}
void authErrorPopUp() {
Widget alertpopUp = MihPackageAlert(
alertIcon: Icon(
Icons.fingerprint,
color: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
size: 100,
),
alertTitle: "Biometric Authentication Required",
alertBody: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Hi there! To jump into the ${widget.appName} Package, you'll need to authenticate yourself with your devices biometrics, please set up biometric authentication (like fingerprint, face ID, pattern or pin) on your device first.\n\nIf you have already set up biometric authentication, press \"Authenticate now\" to try again or press \"Set Up Authentication\" to go to your device settings.",
style: TextStyle(
fontSize: 15,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
const SizedBox(height: 20),
Wrap(
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 10,
runSpacing: 10,
children: [
MihButton(
onPressed: () {
AppSettings.openAppSettings(
type: AppSettingsType.security,
);
Navigator.of(context).pop();
},
buttonColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
width: 300,
child: Text(
"Set Up Authentication",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
MihButton(
onPressed: () {
Navigator.of(context).pop();
authenticateUser();
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
width: 300,
child: Text(
"Authenticate Now",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
],
),
alertColour: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
showDialog(
context: context,
builder: (context) {
return alertpopUp;
},
);
}
Future<void> authenticateUser() async {
if (widget.authenticateUser != null &&
widget.authenticateUser! &&
!kIsWeb) {
if (await isUserAuthenticated()) {
widget.onTap();
}
} else {
widget.onTap();
}
}
@override
Widget build(BuildContext context) {
return Container(
@@ -57,7 +188,9 @@ class _MihPackageTileState extends State<MihPackageTile> {
// width: widget.iconSize,
// height: widget.iconSize + widget.iconSize / 3,
child: GestureDetector(
onTap: widget.onTap,
onTap: () async {
authenticateUser();
},
onLongPress: null, // Do this later
child: Column(
children: [

View File

@@ -0,0 +1,18 @@
import 'package:flutter/material.dart';
SnackBar MihSnackBar({
required Widget child,
}) {
return SnackBar(
content: child,
shape: StadiumBorder(),
behavior: SnackBarBehavior.floating,
duration: Duration(seconds: 2),
width: null,
action: SnackBarAction(
label: "Dismiss",
onPressed: () {},
),
// elevation: 30,
);
}

View File

@@ -6,6 +6,7 @@ enum Enviroment { dev, prod }
//
abstract class AppEnviroment {
static late String baseAppUrl;
static late String baseApiUrl;
static late String baseAiUrl;
static late String baseFileUrl;
@@ -21,6 +22,7 @@ abstract class AppEnviroment {
{
if (kIsWeb) {
//================= Web Dev Urls =================
baseAppUrl = "http://localhost:80";
baseApiUrl = "http://localhost:8080";
baseFileUrl = "http://localhost:9000";
baseAiUrl = "http://localhost:11434";
@@ -28,12 +30,14 @@ abstract class AppEnviroment {
break;
} else if (Platform.isAndroid) {
//================= Android Dev Urls =================
baseAppUrl = "http://10.0.2.2:80";
baseApiUrl = "http://10.0.2.2:8080";
baseFileUrl = "http://10.0.2.2:9000";
baseAiUrl = "http://10.0.2.2:11434";
bannerAdUnitId = 'ca-app-pub-3940256099942544/9214589741';
} else {
//================= Web & iOS Dev Urls =================
baseAppUrl = "http://localhost:80";
baseApiUrl = "http://localhost:8080";
baseFileUrl = "http://localhost:9000";
baseAiUrl = "http://localhost:11434";
@@ -43,6 +47,7 @@ abstract class AppEnviroment {
}
case Enviroment.prod:
{
baseAppUrl = "https://app.mzansi-innovation-hub.co.za";
baseApiUrl = "https://api.mzansi-innovation-hub.co.za";
baseFileUrl = "https://minio.mzansi-innovation-hub.co.za";
baseAiUrl = "https://ai.mzansi-innovation-hub.co.za";

View File

@@ -0,0 +1,479 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_print_prevew.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/Example/package_test.dart';
import 'package:mzansi_innovation_hub/mih_packages/about_mih/about_mih.dart';
import 'package:mzansi_innovation_hub/mih_packages/access_review/mih_access.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_auth_forgot_password.dart';
import 'package:mzansi_innovation_hub/mih_packages/mih_authentication/mih_auth_password_reset.dart';
import 'package:mzansi_innovation_hub/mih_packages/mih_authentication/mih_authentication.dart';
import 'package:mzansi_innovation_hub/mih_packages/mih_home/mih_home.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_ai/mzansi_ai.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/mzansi_directory.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/mzansi_business_profile_view.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/profile_business_add.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart';
import 'package:ken_logger/ken_logger.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_barcode_scanner.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/mih_wallet.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/pat_manager.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/add_or_view_patient.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/full_screen_file.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_edit.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_profile.dart';
import 'package:supertokens_flutter/supertokens.dart';
class MihGoRouterPaths {
// External
static const String resetPassword = '/auth/reset-password';
static const String privacyPolicyExternal = '/privacy-policy';
static const String termsOfServiceExternal = '/terms-of-service';
// Internal
// static const String authCheck = '/';
static const String mihAuthentication = '/mih-authentication';
static const String mihHome = '/';
static const String notifications = '/notifications';
static const String forgotPassword = '/mih-authentication/forgot-password';
static const String aboutMih = '/about';
static const String mzansiProfileManage = '/mzansi-profile';
static const String mzansiProfileView = '/mzansi-profile/view';
static const String businessProfileSetup = '/business-profile/set-up';
static const String businessProfileManage = '/business-profile/manage';
static const String businessProfileView = '/business-profile/view';
static const String patientProfile = '/patient-profile';
static const String patientProfileSetup = '/patient-profile/set-up';
static const String patientProfileEdit = '/patient-profile/edit';
static const String mzansiWallet = '/mzansi-wallet';
static const String mzansiDirectory = '/mzansi-directory';
static const String mihAccess = '/mih-access';
static const String calendar = '/calendar';
static const String appointments = '/appointments';
static const String patientManager = '/patient-manager';
static const String patientManagerPatient = '/patient-manager/patient';
static const String fileViewer = '/file-veiwer';
static const String printPreview = '/file-veiwer/print-preview';
static const String barcodeScanner = '/scanner';
static const String calculator = '/calculator';
static const String mzansiAi = '/mzansi-ai';
static const String packageDevTest = '/package-dev';
}
class MihGoRouter {
final GoRouter mihRouter = GoRouter(
initialLocation: MihGoRouterPaths.mihHome,
redirect: (BuildContext context, GoRouterState state) async {
final bool isUserSignedIn = await SuperTokens.doesSessionExist();
final unauthenticatedPaths = [
MihGoRouterPaths.mihAuthentication,
MihGoRouterPaths.forgotPassword,
MihGoRouterPaths.resetPassword,
MihGoRouterPaths.aboutMih,
MihGoRouterPaths.businessProfileView,
];
KenLogger.success(
"Redirect Check: ${state.fullPath}, isUserSignedIn: $isUserSignedIn");
if (!isUserSignedIn && !unauthenticatedPaths.contains(state.fullPath)) {
return MihGoRouterPaths.mihAuthentication;
}
if (isUserSignedIn &&
unauthenticatedPaths.contains(state.fullPath) &&
state.fullPath != MihGoRouterPaths.aboutMih &&
state.fullPath != MihGoRouterPaths.businessProfileView) {
return MihGoRouterPaths.mihHome;
}
return null; // Stay on current route
},
routes: [
// ========================== MIH Auth ==================================
GoRoute(
name: "mihAuthentication",
path: MihGoRouterPaths.mihAuthentication,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: mihAuthentication");
return MihAuthentication();
},
),
GoRoute(
name: "forgotPassword",
path: MihGoRouterPaths.forgotPassword,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: forgotPassword");
return const MihAuthForgotPassword();
},
),
GoRoute(
name: "resetPassword",
path: MihGoRouterPaths.resetPassword,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: resetPassword");
String? token = state.uri.queryParameters['token'];
KenLogger.success("token: $token");
if (token == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MihAuthPasswordReset(token: token);
},
),
// ========================== MIH Home ==================================
GoRoute(
name: "mihHome",
path: MihGoRouterPaths.mihHome,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: mihHome");
if (state.extra != null) {
final bool personalSelected = state.extra as bool;
return MihHome(
key: UniqueKey(),
personalSelected: personalSelected,
);
}
return MihHome(
key: UniqueKey(),
personalSelected: true,
);
},
),
// ========================== About MIH ==================================
GoRoute(
name: "aboutMih",
path: MihGoRouterPaths.aboutMih,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: aboutMih");
final int? packageIndex = state.extra as int?;
int index = 0;
if (packageIndex != null) {
index = packageIndex;
}
return AboutMih(packageIndex: index);
},
),
// ========================== Mzansi Profile Personal ==================================
GoRoute(
name: "mzansiProfileManage",
path: MihGoRouterPaths.mzansiProfileManage,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: mzansiProfileManage");
final AppProfileUpdateArguments? args =
state.extra as AppProfileUpdateArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MzansiProfile(arguments: args);
},
),
GoRoute(
name: "mzansiProfileView",
path: MihGoRouterPaths.mzansiProfileView,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: mzansiProfileView");
final AppUser? user = state.extra as AppUser?;
if (user == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MzansiProfileView(user: user);
},
),
// ========================== Mzansi Profile Business ==================================
GoRoute(
name: "businessProfileManage",
path: MihGoRouterPaths.businessProfileManage,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: businessProfileManage");
final BusinessArguments? args = state.extra as BusinessArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MzansiBusinessProfile(
key: UniqueKey(),
arguments: args,
);
},
),
GoRoute(
name: "businessProfileView",
path: MihGoRouterPaths.businessProfileView,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: businessProfileView");
String? businessId = state.uri.queryParameters['business_id'];
KenLogger.success("businessId: $businessId");
final BusinessViewArguments? args =
state.extra as BusinessViewArguments?;
if (args == null && businessId == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MzansiBusinessProfileView(
key: UniqueKey(),
arguments: args,
businessId: businessId,
);
},
),
GoRoute(
name: "businessProfileSetup",
path: MihGoRouterPaths.businessProfileSetup,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: businessProfileSetup");
final AppUser? signedInUser = state.extra as AppUser?;
return ProfileBusinessAdd(signedInUser: signedInUser!);
},
),
// ========================== MIH Calculator ==================================
GoRoute(
name: "mihCalculator",
path: MihGoRouterPaths.calculator,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: mihCalculator");
final bool? personalSelected = state.extra as bool?;
bool personal = true;
if (personalSelected != null) {
personal = personalSelected;
}
return MIHCalculator(personalSelected: personal);
},
),
// ========================== MIH Calculator ==================================
GoRoute(
name: "mihCalendar",
path: MihGoRouterPaths.calendar,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: mihCalendar");
final CalendarArguments? args = state.extra as CalendarArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MzansiCalendar(
key: UniqueKey(),
arguments: args,
);
},
),
// ========================== Mzansi AI ==================================
GoRoute(
name: "mzansiAi",
path: MihGoRouterPaths.mzansiAi,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: mzansiAi");
final MzansiAiArguments? args = state.extra as MzansiAiArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MzansiAi(arguments: args);
},
),
// ========================== Mzansi Wallet ==================================
GoRoute(
name: "mzansiWallet",
path: MihGoRouterPaths.mzansiWallet,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: mzansiWallet");
final WalletArguments? args = state.extra as WalletArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MihWallet(
key: UniqueKey(),
arguments: args,
);
},
),
GoRoute(
name: "barcodeScanner",
path: MihGoRouterPaths.barcodeScanner,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: barcodeScanner");
final TextEditingController? args =
state.extra as TextEditingController?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MihBarcodeScanner(cardNumberController: args);
},
),
// ========================== Test Package ==================================
GoRoute(
name: "testPackage",
path: MihGoRouterPaths.packageDevTest,
builder: (BuildContext context, GoRouterState state) {
KenLogger.success("MihGoRouter: testPackage");
final TestArguments? args = state.extra as TestArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return PackageTest(arguments: args);
},
),
// ========================== MIH Access Controls ==================================
GoRoute(
name: "mihAccess",
path: MihGoRouterPaths.mihAccess,
builder: (BuildContext context, GoRouterState state) {
final AppUser? signedInUser = state.extra as AppUser?;
if (signedInUser == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MihAccess(
key: UniqueKey(),
signedInUser: signedInUser,
);
},
),
// ========================== Patient Profile ==================================
GoRoute(
name: "patientProfile",
path: MihGoRouterPaths.patientProfile,
builder: (BuildContext context, GoRouterState state) {
final PatientViewArguments? args =
state.extra as PatientViewArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return AddOrViewPatient(
key: UniqueKey(),
arguments: args,
);
},
),
GoRoute(
name: "patientProfileEdit",
path: MihGoRouterPaths.patientProfileEdit,
builder: (BuildContext context, GoRouterState state) {
final PatientEditArguments? args =
state.extra as PatientEditArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return EditPatient(
signedInUser: args.signedInUser,
selectedPatient: args.selectedPatient,
);
},
),
GoRoute(
name: "patientManager",
path: MihGoRouterPaths.patientManager,
builder: (BuildContext context, GoRouterState state) {
final PatManagerArguments? args = state.extra as PatManagerArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return PatManager(
key: UniqueKey(),
arguments: args,
);
},
),
GoRoute(
name: "patientManagerPatient",
path: MihGoRouterPaths.patientManagerPatient,
builder: (BuildContext context, GoRouterState state) {
final PatientViewArguments? args =
state.extra as PatientViewArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return PatientProfile(arguments: args);
},
),
// ========================== Mzansi Directory ==================================
GoRoute(
name: "mzansiDirectory",
path: MihGoRouterPaths.mzansiDirectory,
builder: (BuildContext context, GoRouterState state) {
final MzansiDirectoryArguments? args =
state.extra as MzansiDirectoryArguments?;
if (args == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go(MihGoRouterPaths.mihHome);
});
return const SizedBox.shrink();
}
return MzansiDirectory(arguments: args);
},
),
// ========================== End ==================================
GoRoute(
name: "fileViewer",
path: MihGoRouterPaths.fileViewer,
builder: (BuildContext context, GoRouterState state) {
final FileViewArguments? args = state.extra as FileViewArguments?;
return FullScreenFileViewer(arguments: args!);
},
),
GoRoute(
name: "printPreview",
path: MihGoRouterPaths.printPreview,
builder: (BuildContext context, GoRouterState state) {
final PrintPreviewArguments? args =
state.extra as PrintPreviewArguments?;
return MIHPrintPreview(arguments: args!);
},
),
// ========================== End ==================================
// GoRoute(
// name: "notifications",
// path: MihGoRouterPaths.notifications,
// builder: (BuildContext context, GoRouterState state) {
// final NotificationArguments? args = state.extra as NotificationArguments?;
// return MIHNotificationMessage(arguments: args!);
// },
// ),
],
// 3. Error handling with `errorBuilder` and `redirect`
errorBuilder: (BuildContext context, GoRouterState state) {
KenLogger.error('Invalid Route');
return const Placeholder();
},
);
}

View File

@@ -1,358 +0,0 @@
import 'package:flutter/material.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_print_prevew.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/Example/package_test.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_notification_message.dart';
import 'package:mzansi_innovation_hub/mih_packages/about_mih/about_mih.dart';
import 'package:mzansi_innovation_hub/mih_packages/about_mih/mih_policy_tos_ext/mih_privacy_polocy_external.dart';
import 'package:mzansi_innovation_hub/mih_packages/about_mih/mih_policy_tos_ext/mih_terms_of_service_external.dart';
import 'package:mzansi_innovation_hub/mih_packages/access_review/mih_access.dart';
import 'package:mzansi_innovation_hub/mih_packages/authentication/auth_check.dart';
import 'package:mzansi_innovation_hub/mih_packages/authentication/forgot_password.dart';
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_directory/mzansi_directory.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/mzansi_business_profile_view.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/profile_business_add.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_barcode_scanner.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/mih_wallet.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_manager/pat_manager.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/add_or_view_patient.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/components/full_screen_file.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_add.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_edit.dart';
import 'package:mzansi_innovation_hub/mih_packages/patient_profile/pat_profile/patient_profile.dart';
// 1. Define Route Names as Constants
// This prevents typos and allows for easier refactoring.
// Consider moving this to a separate `lib/constants/app_routes.dart` file
// if your project grows larger.
class AppRoutes {
// External
static const String resetPasswordExternal = '/auth/reset-password';
static const String privacyPolicyExternal = '/privacy-policy';
static const String termsOfServiceExternal = '/terms-of-service';
// 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';
static const String mzansiProfile = '/mzansi-profile';
static const String mzansiProfileView = '/mzansi-profile/view';
static const String businessProfileSetup = '/business-profile/set-up';
static const String businessProfileManage = '/business-profile/manage';
static const String businessProfileView = '/business-profile/view';
static const String patientProfile = '/patient-profile';
static const String patientProfileSetup = '/patient-profile/set-up';
static const String patientProfileEdit = '/patient-profile/edit';
static const String mzansiWallet = '/mzansi-wallet';
static const String mzansiDirectory = '/mzansi-directory';
static const String mihAccess = '/mih-access';
static const String calendar = '/calendar';
static const String appointments = '/appointments';
static const String patientManager = '/patient-manager';
static const String patientManagerPatient = '/patient-manager/patient';
static const String fileViewer = '/file-veiwer';
static const String printPreview = '/file-veiwer/print-preview';
static const String barcodeScanner = '/scanner';
static const String calculator = '/calculator';
static const String mzansiAi = '/mzansi-ai';
static const String packageDevTest = '/package-dev';
}
class RouteGenerator {
static Route<dynamic> generateRoute(RouteSettings settings) {
final args = settings.arguments;
final extPath =
Uri.base.path; // Moved outside the internal switch for clarity
// 2. Prioritize External Links
// Using an if-else if chain for external routes might be slightly
// more performant than a switch if there are many external routes,
// as it avoids string hashing for each case. For a small number,
// a switch is also fine.
if (extPath == AppRoutes.resetPasswordExternal) {
return MaterialPageRoute(
settings: settings,
builder: (_) => ResetPassword(token: Uri.base.queryParameters['token']),
);
} else if (extPath == AppRoutes.privacyPolicyExternal) {
return MaterialPageRoute(
settings: settings,
builder: (_) => const MIHPrivacyPolocyExternal(),
);
} else if (extPath == AppRoutes.termsOfServiceExternal) {
return MaterialPageRoute(
settings: settings,
builder: (_) => const MIHTermsOfServiceExternal(),
);
}
// 3. Handle Internal Navigation with a Switch Statement
// This switch now only deals with internal app routes, making it cleaner.
switch (settings.name) {
case AppRoutes.authCheck:
if (args is AuthArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => AuthCheck(
personalSelected: args.personalSelected,
firstBoot: args.firstBoot,
),
);
}
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.mzansiDirectory:
if (args is MzansiDirectoryArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MzansiDirectory(arguments: args),
);
}
break;
case AppRoutes.notifications:
if (args is NotificationArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MIHNotificationMessage(arguments: args),
);
}
break;
case AppRoutes.forgotPassword:
return MaterialPageRoute(
settings: settings, builder: (_) => const ForgotPassword());
case AppRoutes.aboutMih:
if (args is int) {
return MaterialPageRoute(
settings: settings,
builder: (_) => AboutMih(packageIndex: args),
);
} else {
return MaterialPageRoute(
settings: settings,
builder: (_) => AboutMih(),
);
}
case AppRoutes.mzansiProfile:
if (args is AppProfileUpdateArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MzansiProfile(arguments: args),
);
}
break;
case AppRoutes.mzansiProfileView:
if (args is AppUser) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MzansiProfileView(user: args),
);
}
break;
case AppRoutes.businessProfileSetup:
if (args is AppUser) {
return MaterialPageRoute(
settings: settings,
builder: (_) => ProfileBusinessAdd(signedInUser: args),
);
}
break;
case AppRoutes.businessProfileManage:
if (args is BusinessArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MzansiBusinessProfile(arguments: args),
);
}
break;
case AppRoutes.businessProfileView:
if (args is BusinessViewArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MzansiBusinessProfileView(arguments: args),
);
}
break;
case AppRoutes.patientProfile:
if (args is PatientViewArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => AddOrViewPatient(arguments: args),
);
}
break;
case AppRoutes.patientProfileSetup:
if (args is AppUser) {
return MaterialPageRoute(
settings: settings,
builder: (_) => AddPatient(signedInUser: args),
);
}
break;
case AppRoutes.patientProfileEdit:
if (args is PatientEditArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => EditPatient(
signedInUser: args.signedInUser,
selectedPatient: args.selectedPatient,
),
);
}
break;
case AppRoutes.mzansiWallet:
if (args is WalletArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MihWallet(arguments: args),
);
}
break;
case AppRoutes.mihAccess:
if (args is AppUser) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MihAccess(signedInUser: args),
);
}
break;
// 4. Handle Calendar/Appointments - Unified to one case or keep separate as needed
case AppRoutes.calendar:
case AppRoutes
.appointments: // Fall-through if both lead to the same screen
if (args is CalendarArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MzansiCalendar(arguments: args),
);
}
break;
case AppRoutes.patientManager:
if (args is PatManagerArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => PatManager(arguments: args),
);
}
break;
case AppRoutes.patientManagerPatient:
if (args is PatientViewArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => PatientProfile(arguments: args),
);
}
break;
case AppRoutes.fileViewer:
if (args is FileViewArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => FullScreenFileViewer(arguments: args),
);
}
break;
case AppRoutes.printPreview:
if (args is PrintPreviewArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MIHPrintPreview(arguments: args),
);
}
break;
case AppRoutes.barcodeScanner:
if (args is TextEditingController) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MihBarcodeScanner(cardNumberController: args),
);
}
break;
case AppRoutes.calculator:
if (args is bool) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MIHCalculator(personalSelected: args),
);
}
break;
case AppRoutes.mzansiAi:
if (args is MzansiAiArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => MzansiAi(arguments: args),
);
}
break;
case AppRoutes.packageDevTest:
if (args is TestArguments) {
return MaterialPageRoute(
settings: settings,
builder: (_) => PackageTest(arguments: args),
);
}
break;
default:
// If no match is found, fall through to the error route
break;
}
// 5. Consolidated Error Route Call
// If any of the internal cases fail (e.g., wrong argument type or no matching route),
// it will fall through here.
return _errorRoute();
}
// 6. Refined Error Route
// Providing a simple, clear error message or redirection.
static Route<dynamic> _errorRoute() {
debugPrint(
"Invalid Route or Missing/Incorrect Arguments"); // Use debugPrint for development logs
return MaterialPageRoute(
settings: const RouteSettings(name: AppRoutes.authCheck),
builder: (_) => const AuthCheck(
personalSelected: true,
firstBoot: true,
),
);
}
}

View File

@@ -14,7 +14,7 @@ class MihTheme {
late String loadingAssetText;
late TargetPlatform platform;
bool kIsWeb = const bool.fromEnvironment('dart.library.js_util');
String latestVersion = "1.1.15";
String latestVersion = "1.2.0";
// Options:-
// f3f9d2 = Cream
// f0f0c9 = cream2

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.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';
@@ -25,7 +26,7 @@ class _AboutMihState extends State<AboutMih> {
void initState() {
super.initState();
setState(() {
if(widget.packageIndex == null) {
if (widget.packageIndex == null) {
_selcetedIndex = 0;
} else {
_selcetedIndex = widget.packageIndex!;
@@ -55,7 +56,10 @@ class _AboutMihState extends State<AboutMih> {
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
Navigator.of(context).pop();
context.goNamed(
'mihHome',
extra: true,
);
FocusScope.of(context).unfocus();
},
);

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart';
import 'package:flutter/material.dart';
@@ -20,10 +21,14 @@ class _AboutMihTileState extends State<AboutMihTile> {
Widget build(BuildContext context) {
return MihPackageTile(
onTap: () {
Navigator.of(context).pushNamed(
'/about',
arguments: 0,
context.goNamed(
"aboutMih",
extra: 0,
);
// Navigator.of(context).pushNamed(
// '/about',
// arguments: 0,
// );
},
appName: "About MIH",
appIcon: Icon(

View File

@@ -1,11 +1,13 @@
import 'package:flutter/material.dart';
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/mih_components/mih_package_components/mih_package_alert.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_service_calls.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_access_controls_services.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_window.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_success_message.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_warning_message.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_env.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart';
@@ -14,11 +16,13 @@ import 'package:mzansi_innovation_hub/mih_components/mih_objects/patient_access.
class BuildBusinessAccessList extends StatefulWidget {
final List<PatientAccess> patientAccessList;
final AppUser signedInUser;
final void Function()? onSuccessUpate;
const BuildBusinessAccessList({
super.key,
required this.patientAccessList,
required this.signedInUser,
required this.onSuccessUpate,
});
@override
@@ -47,18 +51,6 @@ class _BuildPatientsListState extends State<BuildBusinessAccessList> {
);
}
void successPopUp(String message) {
showDialog(
context: context,
builder: (context) {
return MIHSuccessMessage(
successType: "Success",
successMessage: message,
);
},
);
}
void accessCancelledWarning() {
showDialog(
context: context,
@@ -352,9 +344,10 @@ class _BuildPatientsListState extends State<BuildBusinessAccessList> {
spacing: 10,
children: [
MihButton(
onPressed: () {
onPressed: () async {
print("request declined");
MIHApiCalls.updatePatientAccessAPICall(
int statusCode = await MihAccessControlsServices()
.updatePatientAccessAPICall(
widget.patientAccessList[index].business_id,
widget.patientAccessList[index].requested_by,
widget.patientAccessList[index].app_id,
@@ -363,6 +356,13 @@ class _BuildPatientsListState extends State<BuildBusinessAccessList> {
widget.signedInUser,
context,
);
if (statusCode == 200) {
context.pop();
successPopUp("Successfully Actioned Request",
"You have successfully Declined access request");
} else {
internetConnectionPopUp();
}
},
buttonColor: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode ==
@@ -380,9 +380,10 @@ class _BuildPatientsListState extends State<BuildBusinessAccessList> {
),
),
MihButton(
onPressed: () {
onPressed: () async {
print("request approved");
MIHApiCalls.updatePatientAccessAPICall(
int statusCode = await MihAccessControlsServices()
.updatePatientAccessAPICall(
widget.patientAccessList[index].business_id,
widget.patientAccessList[index].requested_by,
widget.patientAccessList[index].app_id,
@@ -391,6 +392,13 @@ class _BuildPatientsListState extends State<BuildBusinessAccessList> {
widget.signedInUser,
context,
);
if (statusCode == 200) {
context.pop();
successPopUp("Successfully Actioned Request",
"You have successfully Accepted access request");
} else {
internetConnectionPopUp();
}
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
@@ -421,6 +429,64 @@ class _BuildPatientsListState extends State<BuildBusinessAccessList> {
);
}
void successPopUp(String title, String message) {
showDialog(
context: context,
builder: (context) {
return MihPackageAlert(
alertIcon: Icon(
Icons.check_circle_outline_rounded,
size: 150,
color: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
alertTitle: title,
alertBody: Column(
children: [
Text(
message,
style: TextStyle(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 25),
Center(
child: MihButton(
onPressed: () {
context.pop();
KenLogger.warning("dismissing pop up and refreshing list");
if (widget.onSuccessUpate != null) {
widget.onSuccessUpate!();
}
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
elevation: 10,
width: 300,
child: Text(
"Dismiss",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
)
],
),
alertColour: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
},
);
}
@override
void dispose() {
super.dispose();

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.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';
@@ -40,7 +41,10 @@ class _MihAccessState extends State<MihAccess> {
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
Navigator.of(context).pop();
context.goNamed(
'mihHome',
extra: true,
);
FocusScope.of(context).unfocus();
},
);

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart';
@@ -23,11 +24,16 @@ class _MihAccessTileState extends State<MihAccessTile> {
@override
Widget build(BuildContext context) {
return MihPackageTile(
authenticateUser: true,
onTap: () {
Navigator.of(context).pushNamed(
'/mih-access',
arguments: widget.signedInUser,
context.goNamed(
"mihAccess",
extra: widget.signedInUser,
);
// Navigator.of(context).pushNamed(
// '/mih-access',
// arguments: widget.signedInUser,
// );
},
appName: "Access Controls",
appIcon: Icon(

View File

@@ -1,3 +1,5 @@
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/mih_components/mih_package_components/mih_icons.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
@@ -5,7 +7,6 @@ import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.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_dropdwn_field.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
import 'package:flutter/material.dart';
import '../../../mih_services/mih_service_calls.dart';
import '../../../mih_components/mih_layout/mih_action.dart';
@@ -105,12 +106,11 @@ class _MihAccessRequestState extends State<MihAccessRequest> {
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).popAndPushNamed(
'/',
arguments: AuthArguments(true, false),
context.goNamed(
'mihHome',
extra: false,
);
FocusScope.of(context).unfocus();
},
);
}
@@ -164,6 +164,7 @@ class _MihAccessRequestState extends State<MihAccessRequest> {
setState(() {
forceRefresh = true;
});
KenLogger.warning("Refreshing Access List");
refreshList();
},
icon: const Icon(
@@ -186,6 +187,12 @@ class _MihAccessRequestState extends State<MihAccessRequest> {
return BuildBusinessAccessList(
signedInUser: widget.signedInUser,
patientAccessList: accessRequestList,
onSuccessUpate: () {
setState(() {
forceRefresh = true;
});
refreshList();
},
);
} else {
return Padding(

View File

@@ -1,92 +0,0 @@
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';
class AuthCheck extends StatefulWidget {
final bool personalSelected;
final bool firstBoot;
const AuthCheck({
super.key,
required this.personalSelected,
required this.firstBoot,
});
@override
State<AuthCheck> createState() => _AuthCheckState();
}
class _AuthCheckState extends State<AuthCheck> {
// final _noScreenshot = NoScreenshot.instance;
Future<bool> doesSessionExist() async {
//wait
//await Future.delayed(const Duration(seconds: 1));
bool signedIn = await SuperTokens.doesSessionExist();
return signedIn;
}
// void disableScreenshot() async {
// try {
// bool result = await _noScreenshot.screenshotOff();
// print('Screenshot Off: $result');
// } on Exception {
// print("Web");
// }
// }
@override
void initState() {
//signedIn = doesSessionExist();
// disableScreenshot(); Screenshot
// var brightness =
// SchedulerBinding.instance.platformDispatcher.platformBrightness;
// bool isDarkMode = brightness == Brightness.dark;
// if (isDarkMode) {
// MzansiInnovationHub.of(context)!.theme.mode = "Dark";
// } else {
// MzansiInnovationHub.of(context)!.theme.mode = "Light";
// }
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
// Return a widget tree based on the orientation
return FutureBuilder(
future: doesSessionExist(),
builder: (context, snapshot) {
//print(snapshot.data);
if (snapshot.data == true) {
return BiometricCheck(
personalSelected: widget.personalSelected,
firstBoot: widget.firstBoot,
);
} else if (snapshot.data == false) {
return MihAuthentication();
} else {
return
// const SizedBox(width: 5, height: 5);
const Mihloadingcircle();
}
});
},
// child: FutureBuilder(
// future: signedIn,
// builder: (context, snapshot) {
// if (snapshot.data == true) {
// return const MIHProfileGetter();
// } else {
// return const SignInOrRegister();
// }
// }),
),
);
}
}

View File

@@ -1,300 +0,0 @@
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_action.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_body.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_header.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_layout_builder.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_alert.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_packages/mih_home/mih_profile_getter.dart';
import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.dart';
import 'package:supertokens_flutter/supertokens.dart';
import 'package:app_settings/app_settings.dart';
class BiometricCheck extends StatefulWidget {
final bool personalSelected;
final bool firstBoot;
const BiometricCheck({
super.key,
required this.personalSelected,
required this.firstBoot,
});
@override
State<BiometricCheck> createState() => _BiometricCheckState();
}
class _BiometricCheckState extends State<BiometricCheck> {
bool _isBioAuthenticated = false;
final LocalAuthentication _auth = LocalAuthentication();
MIHAction getActionButton() {
return MIHAction(
icon: Padding(
padding: const EdgeInsets.all(10.0),
child: SizedBox(
height: 50,
child: FittedBox(
child: Icon(
MihIcons.mihLogo,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
),
),
iconSize: 35,
onTap: () async {
await SuperTokens.signOut(completionHandler: (error) {
print(error);
});
if (await SuperTokens.doesSessionExist() == false) {
Navigator.of(context).popAndPushNamed('/');
}
// Navigator.of(context).pushNamed(
// '/about',
// //arguments: widget.signedInUser,
// );
},
);
}
MIHHeader getHeader() {
return const MIHHeader(
headerAlignment: MainAxisAlignment.center,
headerItems: [
Text(
"",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 25,
),
),
],
);
}
void authenticateUser() async {
final bool canAuthWithBio = await _auth.canCheckBiometrics;
final bool canAuthenticate =
canAuthWithBio || await _auth.isDeviceSupported();
print("Auth Available: $canAuthenticate");
if (canAuthenticate) {
try {
final bool didBioAuth = await _auth.authenticate(
localizedReason: "Authenticate to access MIH",
options: const AuthenticationOptions(
biometricOnly: false,
),
);
if (didBioAuth) {
setState(() {
_isBioAuthenticated = true;
});
} else {
authErrorPopUp();
}
// print("Authenticated: $didBioAuth");
} catch (error) {
print("Auth Error: $error");
authErrorPopUp();
}
} else {
print("Auth Error: No Biometrics Available");
authErrorPopUp();
}
}
void authErrorPopUp() {
Widget alertpopUp = MihPackageAlert(
alertIcon: Icon(
Icons.fingerprint,
color: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
size: 100,
),
alertTitle: "Biometric Authentication Error",
alertBody: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Hi there! To jump into the MIH Home Package, you'll need to authenticate yourself with your phones biometrics, please set up biometric authentication (like fingerprint, face ID, pattern or pin) on your device first.\n\nIf you have already set up biometric authentication, press \"Authenticate now\" to try again or press \"Set Up Authentication\" to go to your device settings.",
style: TextStyle(
fontSize: 15,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
const SizedBox(height: 20),
Wrap(
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 10,
runSpacing: 10,
children: [
MihButton(
onPressed: () {
AppSettings.openAppSettings(
type: AppSettingsType.security,
);
Navigator.of(context).pop();
},
buttonColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
width: 300,
child: Text(
"Set Up Authentication",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
MihButton(
onPressed: () {
Navigator.of(context).pop();
authenticateUser();
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
width: 300,
child: Text(
"Authenticate Now",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
],
),
alertColour: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
showDialog(
context: context,
builder: (context) {
return alertpopUp;
},
);
}
MIHBody getBody() {
return MIHBody(
borderOn: false,
bodyItems: [
SafeArea(
child: Center(
child: Padding(
padding: const EdgeInsets.all(25.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//logo
Icon(
Icons.fingerprint,
size: 100,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
//spacer
const SizedBox(height: 10),
//Heading
Text(
'Biomentric Authentication',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
//spacer
const SizedBox(height: 25),
// if (!_isBioAuthenticated)
Icon(
Icons.lock,
size: 200,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
const SizedBox(height: 30),
MihButton(
onPressed: () {
authenticateUser();
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
width: 300,
child: Text(
"Authenticate Now",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
),
),
],
);
}
Widget getBiomentricAuthScreen() {
return MIHLayoutBuilder(
actionButton: getActionButton(),
header: getHeader(),
secondaryActionButton: null,
body: getBody(),
actionDrawer: null,
secondaryActionDrawer: null,
bottomNavBar: null,
pullDownToRefresh: false,
onPullDown: () async {},
);
}
@override
void initState() {
// TODO: implement initState
super.initState();
if (widget.firstBoot == true) authenticateUser();
}
@override
Widget build(BuildContext context) {
if (MzansiInnovationHub.of(context)!.theme.getPlatform() == "Web") {
return MIHProfileGetter(
personalSelected: widget.personalSelected,
);
} else if (!widget.firstBoot) {
return MIHProfileGetter(
personalSelected: widget.personalSelected,
);
} else {
if (_isBioAuthenticated) {
return MIHProfileGetter(
personalSelected: widget.personalSelected,
);
} else {
return getBiomentricAuthScreen();
}
}
}
}

View File

@@ -1,352 +0,0 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.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_alert.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart';
import '../../main.dart';
import 'package:supertokens_flutter/http.dart' as http;
import '../../mih_components/mih_layout/mih_action.dart';
import '../../mih_components/mih_layout/mih_body.dart';
import '../../mih_components/mih_layout/mih_header.dart';
import '../../mih_components/mih_layout/mih_layout_builder.dart';
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
import '../../mih_config/mih_env.dart';
class ForgotPassword extends StatefulWidget {
const ForgotPassword({super.key});
@override
State<ForgotPassword> createState() => _ForgotPasswordState();
}
class _ForgotPasswordState extends State<ForgotPassword> {
final emailController = TextEditingController();
final _formKey = GlobalKey<FormState>();
//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 Exception {
Navigator.of(context).pop();
//loginError();
}
}
Color getPrim() {
return MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
}
Color getSec() {
return MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
}
void prePassResteWarning() {
showDialog(
context: context,
builder: (context) {
return MihPackageAlert(
alertIcon: Icon(
Icons.warning_amber_rounded,
size: 100,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
alertTitle: "Password Reset Confirmation",
alertBody: Column(
//mainAxisSize: MainAxisSize.max,
children: [
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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 25),
MihButton(
onPressed: () {
setState(() {
acceptWarning = true;
});
Navigator.of(context).pop();
validateInput();
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
width: 300,
child: Text(
"Continue",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
alertColour: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
},
);
}
void loginError() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Invalid Credentials");
},
);
}
void resetLinkSentSuccessfully() {
showDialog(
context: context,
builder: (context) {
return const MIHSuccessMessage(
successType: "Success",
successMessage:
"We've sent a password reset link to your email address. Please check your inbox, including spam or junk folders.\n\nOnce you find the email, click on the link to reset your password.\n\nIf you don't receive the email within a few minutes, please try resending the reset request.\n\nThe reset link will expire after 2 hours");
},
);
}
void validateInput() async {
if (emailController.text.isEmpty) {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Input Error");
},
);
} else {
await submitPasswodReset();
if (successfulForgotPassword) {
Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
resetLinkSentSuccessfully();
}
}
}
MIHAction getActionButton() {
return MIHAction(
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
Navigator.of(context).pop();
},
);
}
MIHHeader getHeader() {
return const MIHHeader(
headerAlignment: MainAxisAlignment.center,
headerItems: [
Text(
"",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 25,
),
),
],
);
}
MIHBody getBody(double width) {
return MIHBody(
borderOn: false,
bodyItems: [
KeyboardListener(
focusNode: _focusNode,
autofocus: true,
onKeyEvent: (event) async {
if (event is KeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.enter) {
validateInput();
}
},
child: SafeArea(
child: Center(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Padding(
padding: MzansiInnovationHub.of(context)!.theme.screenType ==
"desktop"
? EdgeInsets.symmetric(
vertical: 25, horizontal: width * 0.2)
: EdgeInsets.symmetric(
vertical: 25, horizontal: width * 0.075),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//logo
Icon(
Icons.lock,
size: 100,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
//spacer
const SizedBox(height: 10),
//Heading
Text(
'Forgot Password',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
const SizedBox(height: 25),
MihForm(
formKey: _formKey,
formFields: [
MihTextFormField(
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
controller: emailController,
multiLineInput: false,
requiredText: true,
hintText: "Email",
validator: (value) {
return MihValidationServices()
.validateEmail(value);
},
),
//spacer
const SizedBox(height: 20),
Align(
alignment: Alignment.center,
child: MihButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
prePassResteWarning();
} else {
MihAlertServices()
.formNotFilledCompletely(context);
}
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"Reset Password",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
],
),
),
),
),
),
),
],
);
}
@override
void dispose() {
emailController.dispose();
_focusNode.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return MIHLayoutBuilder(
actionButton: getActionButton(),
header: getHeader(),
secondaryActionButton: null,
body: getBody(screenWidth),
actionDrawer: null,
secondaryActionDrawer: null,
bottomNavBar: null,
pullDownToRefresh: false,
onPullDown: () async {},
);
}
}

View File

@@ -1,518 +0,0 @@
import 'dart:convert';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_install_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.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_icons.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../main.dart';
import 'package:supertokens_flutter/http.dart' as http;
import 'package:supertokens_flutter/supertokens.dart';
import '../../mih_components/mih_layout/mih_action.dart';
import '../../mih_components/mih_layout/mih_body.dart';
import '../../mih_components/mih_layout/mih_header.dart';
import '../../mih_components/mih_layout/mih_layout_builder.dart';
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
import '../../mih_config/mih_env.dart';
class Register extends StatefulWidget {
final Function()? onTap;
const Register({super.key, required this.onTap});
@override
State<Register> createState() => _RegisterState();
}
class _RegisterState extends State<Register> {
final emailController = TextEditingController();
final passwordController = TextEditingController();
final confirmPasswordController = TextEditingController();
final officeID = TextEditingController();
final baseAPI = AppEnviroment.baseApiUrl;
final FocusNode _focusNode = FocusNode();
final _formKey = GlobalKey<FormState>();
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,
arguments: AuthArguments(
true,
true,
),
);
// 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"]) {
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();
}
}
}
bool validEmail() {
String text = emailController.text;
var regex = RegExp(r'^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$');
return regex.hasMatch(text);
}
void internetConnectionPopUp() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Internet Connection");
},
);
}
void signUpSuccess() {
showDialog(
context: context,
builder: (context) {
return const MIHSuccessMessage(
successType: "Success",
successMessage:
"Congratulations! Your account has been created successfully. You are logged in and can start exploring.\n\nPlease note: more apps will appear once you update your profile.");
},
);
}
void signUpError() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "User Exists");
},
);
}
void passwordError() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Password Match");
},
);
}
void emailError() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Invalid Email");
},
);
}
void passwordReqError() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Password Requirements");
},
);
}
void loginError(error) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(error),
);
},
);
}
void submitFormInput() async {
await signUserUp();
}
void toggle() {
setState(() {
_obscureText = !_obscureText;
});
}
Widget getSecondaryActionButton() {
return Visibility(
visible: MzansiInnovationHub.of(context)!.theme.getPlatform() == "Web",
child: MIHAction(
icon: Padding(
padding: const EdgeInsets.all(10.0),
child: MihButton(
onPressed: () {
MihInstallServices().installMihTrigger(context);
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
width: 150,
child: Text(
"Install MIH",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
),
iconSize: 35,
onTap: () {
MihInstallServices().installMihTrigger(context);
},
),
);
}
MIHAction getActionButton() {
return MIHAction(
icon: Padding(
padding: const EdgeInsets.all(10.0),
child: SizedBox(
height: 50,
child: FittedBox(
child: Icon(
MihIcons.mihLogo,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
),
),
iconSize: 35,
onTap: () {
Navigator.of(context).pushNamed(
'/about',
arguments: 0,
);
},
);
}
MIHHeader getHeader() {
return const MIHHeader(
headerAlignment: MainAxisAlignment.center,
headerItems: [
Text(
"",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 25,
),
),
],
);
}
MIHBody getBody(double width) {
return MIHBody(
borderOn: false,
bodyItems: [
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: SafeArea(
child: Center(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Padding(
padding: MzansiInnovationHub.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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
//spacer
const SizedBox(height: 10),
//Heading
Text(
'Create an Account',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
//spacer
// const SizedBox(height: 20),
MihForm(
formKey: _formKey,
formFields: [
//email input
MihTextFormField(
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
width: 300,
child: Text(
"Create New Account",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
MihButton(
onPressed: widget.onTap,
buttonColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
width: 300,
child: Text(
"I have an account",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
//here
],
)
],
),
),
),
)),
),
],
);
}
@override
void dispose() {
emailController.dispose();
passwordController.dispose();
officeID.dispose();
_focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return MIHLayoutBuilder(
actionButton: getActionButton(),
header: getHeader(),
secondaryActionButton: getSecondaryActionButton(),
body: getBody(screenWidth),
actionDrawer: null,
secondaryActionDrawer: null,
bottomNavBar: null,
pullDownToRefresh: false,
onPullDown: () async {},
);
}
}

View File

@@ -1,353 +0,0 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.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_text_form_field.dart';
import '../../main.dart';
import 'package:supertokens_flutter/http.dart' as http;
import '../../mih_components/mih_layout/mih_action.dart';
import '../../mih_components/mih_layout/mih_body.dart';
import '../../mih_components/mih_layout/mih_header.dart';
import '../../mih_components/mih_layout/mih_layout_builder.dart';
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
import '../../mih_config/mih_env.dart';
class ResetPassword extends StatefulWidget {
final String? token;
const ResetPassword({
super.key,
required this.token,
});
@override
State<ResetPassword> createState() => _ResetPasswordState();
}
class _ResetPasswordState extends State<ResetPassword> {
final passwordController = TextEditingController();
final confirmPasswordController = TextEditingController();
//bool _obscureText = true;
bool successfulResetPassword = false;
bool acceptWarning = false;
// focus node to capture keyboard events
final FocusNode _focusNode = FocusNode();
final _formKey = GlobalKey<FormState>();
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 Exception {
Navigator.of(context).pop();
//loginError();
}
}
void passwordReqError() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Password Requirements");
},
);
}
Color getPrim() {
return MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
}
Color getSec() {
return MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
}
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 submitFormInput() async {
if (passwordController.text != confirmPasswordController.text) {
passwordError();
} else {
await submitPasswodReset();
if (successfulResetPassword) {
resetSuccessfully();
}
}
}
MIHAction getActionButton() {
return MIHAction(
icon: Padding(
padding: const EdgeInsets.all(10.0),
child: SizedBox(
height: 50,
child: Image.asset(
'lib/mih_components/mih_package_components/assets/images/logo_light.png'),
),
),
iconSize: 35,
onTap: () {
// Navigator.of(context).pushNamed(
// '/about',
// //arguments: widget.signedInUser,
// );
},
);
}
MIHHeader getHeader() {
return const MIHHeader(
headerAlignment: MainAxisAlignment.center,
headerItems: [
Text(
"",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 25,
),
),
],
);
}
MIHBody getBody(double width) {
return MIHBody(
borderOn: false,
bodyItems: [
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: SafeArea(
child: Center(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Padding(
padding: MzansiInnovationHub.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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
//spacer
const SizedBox(height: 10),
//Heading
Text(
'Reset Password',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
//spacer
const SizedBox(height: 25),
MihForm(
formKey: _formKey,
formFields: [
MihTextFormField(
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: 25),
// sign in button
Center(
child: MihButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
submitFormInput();
} else {
MihAlertServices()
.formNotFilledCompletely(context);
}
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"Reset Password",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
],
),
),
),
),
),
),
],
);
}
@override
void dispose() {
passwordController.dispose();
confirmPasswordController.dispose();
_focusNode.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return MIHLayoutBuilder(
actionButton: getActionButton(),
header: getHeader(),
secondaryActionButton: null,
body: getBody(screenWidth),
actionDrawer: null,
secondaryActionDrawer: null,
bottomNavBar: null,
pullDownToRefresh: false,
onPullDown: () async {},
);
}
}

View File

@@ -1,701 +0,0 @@
import 'dart:convert';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_install_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.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_icons.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../main.dart';
import 'package:supertokens_flutter/http.dart' as http;
import '../../mih_components/mih_layout/mih_action.dart';
import '../../mih_components/mih_layout/mih_body.dart';
import '../../mih_components/mih_layout/mih_header.dart';
import '../../mih_components/mih_layout/mih_layout_builder.dart';
import '../../mih_components/mih_layout/mih_tile.dart';
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import '../../mih_config/mih_env.dart';
class SignIn extends StatefulWidget {
final Function() onTap;
const SignIn({super.key, required this.onTap});
@override
State<SignIn> createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
final emailController = TextEditingController();
final passwordController = TextEditingController();
//bool _obscureText = true;
bool successfulSignIn = false;
bool showProfiles = false;
// focus node to capture keyboard events
final FocusNode _focusNode = FocusNode();
final _formKey = GlobalKey<FormState>();
final baseAPI = AppEnviroment.baseApiUrl;
late List<MIHTile> sandboxProfileList = [];
//sign user in
Future<void> signUserIn() async {
//var _backgroundColor = Colors.transparent;
showDialog(
context: context,
builder: (context) {
return const Mihloadingcircle();
},
);
try {
var response = await http.post(
Uri.parse("$baseAPI/auth/signin"),
body:
'{"formFields": [{"id": "email","value": "${emailController.text}"}, {"id": "password","value": "${passwordController.text}"}]}',
headers: {
'Content-type': 'application/json',
'Accept': 'application/json',
"Authorization": "leatucczyixqwkqqdrhayiwzeofkltds"
},
);
//print(response.body[])
if (response.statusCode == 200) {
//print(response.body);
var userSignedin = jsonDecode(response.body);
if (userSignedin["status"] == "OK") {
//print("here");
setState(() {
successfulSignIn = true;
});
Navigator.of(context).pop();
} else {
Navigator.of(context).pop();
loginError();
passwordController.clear();
}
}
} on Exception {
Navigator.of(context).pop();
loginError();
passwordController.clear();
}
}
Color getPrim() {
return MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
}
Color getSec() {
return MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
}
void setSandboxProfiles(List<MIHTile> 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(),
));
//}
}
void loginError() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Invalid Credentials");
},
);
}
void submitSignInForm() async {
await signUserIn();
if (successfulSignIn) {
Navigator.of(context).pushNamedAndRemoveUntil(
'/',
(route) => false,
arguments: AuthArguments(
true,
true,
),
);
}
}
void showSandboxProfiles() {
showDialog(
context: context,
builder: (context) {
return Dialog(
//backgroundColor: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
child: Stack(
children: [
Container(
padding: const EdgeInsets.all(10.0),
width: 500.0,
height: 500,
decoration: BoxDecoration(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
borderRadius: BorderRadius.circular(25.0),
border: Border.all(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 5.0),
),
child: Column(
//mainAxisSize: MainAxisSize.max,
children: [
Text(
"Sandbox Profiles",
textAlign: TextAlign.center,
style: TextStyle(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
size: 35,
),
),
),
],
),
);
},
);
}
Widget getSecondaryActionButton() {
return Visibility(
visible: MzansiInnovationHub.of(context)!.theme.getPlatform() == "Web",
child: MIHAction(
icon: Padding(
padding: const EdgeInsets.all(10.0),
child: MihButton(
onPressed: () {
MihInstallServices().installMihTrigger(context);
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
width: 150,
child: Text(
"Install MIH",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
),
iconSize: 35,
onTap: () {
Navigator.of(context).pushNamed(
'/about',
arguments: 0,
);
},
),
);
}
MIHAction getActionButton() {
return MIHAction(
icon: Padding(
padding: const EdgeInsets.all(10.0),
child: SizedBox(
height: 50,
child: FittedBox(
child: Icon(
MihIcons.mihLogo,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
),
),
iconSize: 35,
onTap: () {
Navigator.of(context).pushNamed(
'/about',
arguments: 0,
);
},
);
}
MIHHeader getHeader() {
return const MIHHeader(
headerAlignment: MainAxisAlignment.center,
headerItems: [
Text(
"",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 25,
),
),
],
);
}
MIHBody getBody(double width) {
return MIHBody(
borderOn: false,
bodyItems: [
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: SafeArea(
child: Center(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Padding(
padding: MzansiInnovationHub.of(context)!.theme.screenType ==
"desktop"
? EdgeInsets.symmetric(horizontal: width * 0.2)
: EdgeInsets.symmetric(horizontal: width * 0.075),
child: AutofillGroup(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//logo
Icon(
Icons.lock,
size: 100,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
//spacer
const SizedBox(height: 10),
//Heading
Text(
'Sign In',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
//spacer
const SizedBox(height: 10),
MihForm(
formKey: _formKey,
formFields: [
MihTextFormField(
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
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: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
width: 300,
child: Text(
"Sign In",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
MihButton(
onPressed: widget.onTap,
buttonColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
width: 300,
child: Text(
"Create New Account",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
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:
MihColors.getSecondaryColor(
MzansiInnovationHub.of(
context)!
.theme
.mode ==
"Dark")),
),
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: 20),
Text(
"NB: These accounts are used for test purposes. Please do not store personal information on these profiles.",
textAlign: TextAlign.center,
style: TextStyle(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
),
],
),
],
),
),
),
),
),
),
),
],
);
}
@override
void dispose() {
emailController.dispose();
passwordController.dispose();
_focusNode.dispose();
TextInput.finishAutofillContext();
super.dispose();
}
@override
void initState() {
setState(() {
setSandboxProfiles(sandboxProfileList);
});
super.initState();
}
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return MIHLayoutBuilder(
actionButton: getActionButton(),
header: getHeader(),
secondaryActionButton: getSecondaryActionButton(),
body: getBody(screenWidth),
actionDrawer: null,
secondaryActionDrawer: null,
bottomNavBar: null,
pullDownToRefresh: false,
onPullDown: () async {},
);
}
}

View File

@@ -1,35 +0,0 @@
import 'package:flutter/material.dart';
import 'register.dart';
import 'signin.dart';
class SignInOrRegister extends StatefulWidget {
const SignInOrRegister({super.key});
@override
State<SignInOrRegister> createState() => _SignInOrRegisterState();
}
class _SignInOrRegisterState extends State<SignInOrRegister> {
bool showSignInPage = true;
void togglePages() {
setState(() {
showSignInPage = !showSignInPage;
});
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
if (showSignInPage) {
return SignIn(onTap: togglePages);
} else {
return Register(onTap: togglePages);
}
}
}

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.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';
@@ -42,7 +43,10 @@ class _MIHCalculatorState extends State<MIHCalculator> {
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
Navigator.of(context).pop();
context.goNamed(
'mihHome',
extra: widget.personalSelected,
);
FocusScope.of(context).unfocus();
},
);

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart';
import 'package:flutter/material.dart';
@@ -23,10 +24,14 @@ class _MihCalculatorTileState extends State<MihCalculatorTile> {
Widget build(BuildContext context) {
return MihPackageTile(
onTap: () {
Navigator.of(context).pushNamed(
'/calculator',
arguments: widget.personalSelected,
context.goNamed(
"mihCalculator",
extra: widget.personalSelected,
);
// Navigator.of(context).pushNamed(
// '/calculator',
// arguments: widget.personalSelected,
// );
},
appName: "Calculator",
appIcon: Icon(

View File

@@ -1,5 +1,9 @@
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
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/mih_components/mih_objects/arguments.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_calendar_services.dart';
@@ -198,7 +202,7 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
),
],
onWindowTapClose: () {
Navigator.of(context).pop();
context.pop();
widget.dateController.clear();
widget.timeController.clear();
widget.titleController.clear();
@@ -320,7 +324,7 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
),
],
onWindowTapClose: () {
Navigator.of(context).pop();
context.pop();
widget.dateController.clear();
widget.timeController.clear();
widget.titleController.clear();
@@ -421,7 +425,7 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
.split('T')[1]
.substring(0, 5);
});
Navigator.of(context).pop();
context.pop();
},
windowBody: Padding(
padding:
@@ -552,10 +556,11 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
);
}
void updateAppointmentCall(int index) {
Future<void> updateAppointmentCall(int index) async {
int statusCode;
if (isAppointmentInputValid()) {
if (widget.personalSelected == true) {
MihMzansiCalendarApis.updatePersonalAppointment(
statusCode = await MihMzansiCalendarApis.updatePersonalAppointment(
widget.signedInUser,
widget.business,
null,
@@ -568,7 +573,7 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
);
} else if (widget.personalSelected == false &&
widget.inWaitingRoom == false) {
MihMzansiCalendarApis.updateBusinessAppointment(
statusCode = await MihMzansiCalendarApis.updateBusinessAppointment(
widget.signedInUser,
widget.business,
widget.businessUser,
@@ -580,7 +585,7 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
context,
);
} else {
MihMzansiCalendarApis.updatePatientAppointment(
statusCode = await MihMzansiCalendarApis.updatePatientAppointment(
widget.signedInUser,
widget.business,
widget.businessUser,
@@ -592,6 +597,41 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
context,
);
}
if (statusCode == 200) {
context.pop();
context.pop();
if (!widget.inWaitingRoom) {
KenLogger.warning("calendar route");
context.goNamed(
"mihCalendar",
extra: CalendarArguments(
widget.signedInUser,
widget.personalSelected,
widget.business,
widget.businessUser,
),
);
} else {
KenLogger.warning("waiting room route");
// GoRouter.of(context).refresh();
context.goNamed(
'mihHome',
extra: false,
);
context.goNamed(
'patientManager',
extra: PatManagerArguments(
widget.signedInUser,
false,
widget.business,
widget.businessUser,
),
);
// context.pop();
}
} else {
internetConnectionPopUp();
}
} else {
showDialog(
context: context,
@@ -602,9 +642,8 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
}
}
void deleteAppointmentCall(int index) {
print("personal selected: ${widget.personalSelected}");
MihMzansiCalendarApis.deleteAppointmentAPICall(
Future<void> deleteAppointmentCall(int index) async {
int statucCode = await MihMzansiCalendarApis.deleteAppointmentAPICall(
widget.signedInUser,
widget.personalSelected,
widget.business,
@@ -613,6 +652,82 @@ class _BuildAppointmentListState extends State<BuildAppointmentList> {
widget.appointmentList[index].idappointments,
context,
);
if (statucCode == 200) {
context.pop();
context.pop();
setState(() {
widget.appointmentList.removeAt(index);
});
successPopUp("Successfully Deleted Appointment",
"You appointment has been successfully deleted from your calendar.");
} else {
internetConnectionPopUp();
}
}
void successPopUp(String title, String message) {
showDialog(
context: context,
builder: (context) {
return MihPackageAlert(
alertIcon: Icon(
Icons.check_circle_outline_rounded,
size: 150,
color: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
alertTitle: title,
alertBody: Column(
children: [
Text(
message,
style: TextStyle(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 25),
Center(
child: MihButton(
onPressed: () {
context.pop();
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
elevation: 10,
width: 300,
child: Text(
"Dismiss",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
)
],
),
alertColour: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
},
);
}
void internetConnectionPopUp() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(
errorType: "Internet Connection",
);
},
);
}
bool canEditAppointment(int index) {

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.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';
@@ -41,7 +42,11 @@ class _MzansiCalendarState extends State<MzansiCalendar> {
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
Navigator.of(context).pop();
// Navigator.of(context).pop();
context.goNamed(
'mihHome',
extra: true,
);
FocusScope.of(context).unfocus();
},
);

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart';
@@ -24,10 +25,14 @@ class _MzansiCalendarTileState extends State<MzansiCalendarTile> {
Widget build(BuildContext context) {
return MihPackageTile(
onTap: () {
Navigator.of(context).pushNamed(
'/calendar',
arguments: widget.arguments,
context.goNamed(
"mihCalendar",
extra: widget.arguments,
);
// Navigator.of(context).pushNamed(
// '/calendar',
// arguments: widget.arguments,
// );
},
appName: "Calendar",
appIcon: Icon(

View File

@@ -1,5 +1,7 @@
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:go_router/go_router.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_alert.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_calendar_services.dart';
@@ -143,23 +145,6 @@ class _PatientAccessRequestState extends State<Appointments> {
),
),
);
// return Expanded(
// child: Padding(
// padding: const EdgeInsets.only(top: 35.0),
// child: Align(
// alignment: Alignment.center,
// child: Text(
// "No Appointments for $selectedDay",
// style: TextStyle(
// fontSize: 25,
// color: MihColors.getGreyColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
// ),
// textAlign: TextAlign.center,
// softWrap: true,
// ),
// ),
// ),
// );
}
void addAppointmentWindow(double width) {
@@ -284,10 +269,11 @@ class _PatientAccessRequestState extends State<Appointments> {
}
}
void addAppointmentCall() {
Future<void> addAppointmentCall() async {
if (isAppointmentInputValid()) {
int statusCode;
if (widget.personalSelected == false) {
MihMzansiCalendarApis.addBusinessAppointment(
statusCode = await MihMzansiCalendarApis.addBusinessAppointment(
widget.signedInUser,
widget.business!,
widget.businessUser!,
@@ -299,7 +285,7 @@ class _PatientAccessRequestState extends State<Appointments> {
context,
);
} else {
MihMzansiCalendarApis.addPersonalAppointment(
statusCode = await MihMzansiCalendarApis.addPersonalAppointment(
widget.signedInUser,
_appointmentTitleController.text,
_appointmentDescriptionIDController.text,
@@ -308,6 +294,27 @@ class _PatientAccessRequestState extends State<Appointments> {
context,
);
}
if (statusCode == 201) {
context.pop();
successPopUp("Successfully Added Appointment",
"You appointment has been successfully added to your calendar.");
setState(() {
if (widget.personalSelected) {
appointmentResults = MihMzansiCalendarApis.getPersonalAppointments(
widget.signedInUser.app_id,
selectedDay,
);
} else {
appointmentResults = MihMzansiCalendarApis.getBusinessAppointments(
widget.business!.business_id,
false,
selectedDay,
);
}
});
} else {
internetConnectionPopUp();
}
} else {
showDialog(
context: context,
@@ -319,6 +326,77 @@ class _PatientAccessRequestState extends State<Appointments> {
checkforchange();
}
void successPopUp(String title, String message) {
showDialog(
context: context,
builder: (context) {
return MihPackageAlert(
alertIcon: Icon(
Icons.check_circle_outline_rounded,
size: 150,
color: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
alertTitle: title,
alertBody: Column(
children: [
Text(
message,
style: TextStyle(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 25),
Center(
child: MihButton(
onPressed: () {
context.pop();
setState(() {
_appointmentDateController.clear();
_appointmentTimeController.clear();
_appointmentTitleController.clear();
_appointmentDescriptionIDController.clear();
});
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
elevation: 10,
width: 300,
child: Text(
"Dismiss",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
)
],
),
alertColour: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
},
);
}
void internetConnectionPopUp() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(
errorType: "Internet Connection",
);
},
);
}
String getTitle() {
if (widget.personalSelected == false) {
return "Business Appointments";

View File

@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.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_forgot_password.dart';
class MihAuthForgotPassword extends StatefulWidget {
const MihAuthForgotPassword({super.key});
@override
State<MihAuthForgotPassword> createState() => _MihAuthForgotPasswordState();
}
class _MihAuthForgotPasswordState extends State<MihAuthForgotPassword> {
int _selcetedIndex = 0;
@override
Widget build(BuildContext context) {
return MihPackage(
appActionButton: getAction(),
appTools: getTools(),
appBody: getToolBody(),
selectedbodyIndex: _selcetedIndex,
onIndexChange: (newValue) {
setState(() {
_selcetedIndex = newValue;
});
},
);
}
MihPackageAction getAction() {
return MihPackageAction(
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
context.goNamed(
'mihHome',
extra: true,
);
FocusScope.of(context).unfocus();
},
);
}
MihPackageTools getTools() {
Map<Widget, void Function()?> temp = {};
temp[const Icon(Icons.question_mark_rounded)] = () {
setState(() {
_selcetedIndex = 0;
});
};
return MihPackageTools(
tools: temp,
selcetedIndex: _selcetedIndex,
);
}
List<Widget> getToolBody() {
List<Widget> toolBodies = [
MihForgotPassword(),
];
return toolBodies;
}
}

View File

@@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.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_reset_password.dart';
class MihAuthPasswordReset extends StatefulWidget {
final String token;
const MihAuthPasswordReset({
super.key,
required this.token,
});
@override
State<MihAuthPasswordReset> createState() => _MihAuthPasswordResetState();
}
class _MihAuthPasswordResetState extends State<MihAuthPasswordReset> {
int _selcetedIndex = 0;
@override
Widget build(BuildContext context) {
return MihPackage(
appActionButton: getAction(),
appTools: getTools(),
appBody: getToolBody(),
selectedbodyIndex: _selcetedIndex,
onIndexChange: (newValue) {
setState(() {
_selcetedIndex = newValue;
});
},
);
}
Widget getAction() {
return Padding(
padding: const EdgeInsets.only(left: 5.0),
child: MihPackageAction(
icon: const Icon(MihIcons.mihLogo),
iconSize: 45,
onTap: () {
context.goNamed(
'mihHome',
extra: true,
);
FocusScope.of(context).unfocus();
},
),
);
}
MihPackageTools getTools() {
Map<Widget, void Function()?> temp = {};
temp[const Icon(Icons.password_rounded)] = () {
setState(() {
_selcetedIndex = 0;
});
};
return MihPackageTools(
tools: temp,
selcetedIndex: _selcetedIndex,
);
}
List<Widget> getToolBody() {
List<Widget> toolBodies = [
MihResetPassword(
token: widget.token,
),
];
return toolBodies;
}
}

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.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';
@@ -67,19 +68,16 @@ class _MihAuthenticationState extends State<MihAuthentication> {
);
}
MihPackageAction getAction() {
return MihPackageAction(
icon: Padding(
padding: const EdgeInsets.only(left: 10.0),
child: const Icon(MihIcons.mihLogo),
Widget getAction() {
return Padding(
padding: const EdgeInsets.only(left: 5.0),
child: MihPackageAction(
icon: const Icon(MihIcons.mihLogo),
iconSize: 45,
onTap: () {
context.goNamed("aboutMih", extra: 0);
},
),
iconSize: 45,
onTap: () {
Navigator.of(context).pushNamed(
'/about',
arguments: 0,
);
},
);
}
}

View File

@@ -0,0 +1,295 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.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_alert.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_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_colors.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_validation_services.dart';
class MihForgotPassword extends StatefulWidget {
const MihForgotPassword({super.key});
@override
State<MihForgotPassword> createState() => _MihForgotPasswordState();
}
class _MihForgotPasswordState extends State<MihForgotPassword> {
final emailController = TextEditingController();
bool successfulForgotPassword = false;
final _formKey = GlobalKey<FormState>();
final FocusNode _focusNode = FocusNode();
bool acceptWarning = false;
Future<void> submitPasswodReset() async {
showDialog(
context: context,
builder: (context) {
return const Mihloadingcircle();
},
);
try {
var resetPassEmailSent = await MihAuthenticationServices()
.forgotPassword(emailController.text);
context.pop();
if (resetPassEmailSent) {
setState(() {
successfulForgotPassword = true;
});
}
} on Exception {
//loginError();
}
}
void prePassResteWarning() {
showDialog(
context: context,
builder: (context) {
return MihPackageAlert(
alertIcon: Icon(
Icons.warning_amber_rounded,
size: 100,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
alertTitle: "Password Reset Confirmation",
alertBody: Column(
//mainAxisSize: MainAxisSize.max,
children: [
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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 25),
MihButton(
onPressed: () {
setState(() {
acceptWarning = true;
});
Navigator.of(context).pop();
validateInput();
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
width: 300,
child: Text(
"Continue",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
alertColour: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
},
);
}
void resetLinkSentSuccessfully() {
showDialog(
context: context,
builder: (context) {
return MihPackageAlert(
alertIcon: Icon(
Icons.check_circle_outline_rounded,
size: 150,
color: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
alertTitle: "Successfully Sent Reset Link",
alertBody: Column(
children: [
Text(
"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",
style: TextStyle(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 25),
Center(
child: MihButton(
onPressed: () {
context.goNamed(
'mihHome',
extra: true,
);
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
elevation: 10,
width: 300,
child: Text(
"Dismiss",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
)
],
),
alertColour: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
// 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
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) {
validateInput();
}
},
child: SafeArea(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Padding(
padding: MzansiInnovationHub.of(context)!.theme.screenType ==
"desktop"
? EdgeInsets.symmetric(vertical: 25, horizontal: width * 0.2)
: EdgeInsets.symmetric(vertical: 25, horizontal: width * 0.075),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
//logo
Icon(
Icons.lock,
size: 100,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
//spacer
const SizedBox(height: 10),
//Heading
Text(
'Forgot Password',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
const SizedBox(height: 25),
MihForm(
formKey: _formKey,
formFields: [
MihTextFormField(
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
controller: emailController,
multiLineInput: false,
requiredText: true,
hintText: "Email",
validator: (value) {
return MihValidationServices().validateEmail(value);
},
),
//spacer
const SizedBox(height: 20),
Align(
alignment: Alignment.center,
child: MihButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
prePassResteWarning();
} else {
MihAlertServices().formNotFilledCompletely(context);
}
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"Reset Password",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
],
),
),
),
),
);
}
}

View File

@@ -0,0 +1,266 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.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_alert.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_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_colors.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_validation_services.dart';
class MihResetPassword extends StatefulWidget {
final String token;
const MihResetPassword({
super.key,
required this.token,
});
@override
State<MihResetPassword> createState() => _MihResetPasswordState();
}
class _MihResetPasswordState extends State<MihResetPassword> {
final passwordController = TextEditingController();
final confirmPasswordController = TextEditingController();
final FocusNode _focusNode = FocusNode();
final _formKey = GlobalKey<FormState>();
void submitFormInput() async {
if (passwordController.text != confirmPasswordController.text) {
passwordError();
} else {
showDialog(
context: context,
builder: (context) {
return const Mihloadingcircle();
},
);
bool successfulResetPassword = await MihAuthenticationServices()
.resetPassword(widget.token, passwordController.text);
context.pop();
if (successfulResetPassword) {
resetSuccessfully();
} else {
loginError();
}
}
}
void resetSuccessfully() {
showDialog(
context: context,
builder: (context) {
return MihPackageAlert(
alertIcon: Icon(
Icons.check_circle_outline_rounded,
size: 150,
color: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
alertTitle: "Successfully Reset Password",
alertBody: Column(
children: [
Text(
"Great news! Your password reset is complete. You can now log in to Mzansi Innovation Hub using your new password.",
style: TextStyle(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 25),
Center(
child: MihButton(
onPressed: () {
context.goNamed(
'mihHome',
extra: true,
);
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
elevation: 10,
width: 300,
child: Text(
"Dismiss",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
)
],
),
alertColour: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
// 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 loginError() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Invalid Credentials");
},
);
}
void passwordError() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Password Match");
},
);
}
@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: SafeArea(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Padding(
padding:
MzansiInnovationHub.of(context)!.theme.screenType == "desktop"
? EdgeInsets.symmetric(horizontal: width * 0.2)
: EdgeInsets.symmetric(horizontal: width * 0.075),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Token: ${widget.token}"), // For testing purposes only
//logo
Icon(
Icons.lock,
size: 100,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
//spacer
const SizedBox(height: 10),
//Heading
Text(
'Reset Password',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
//spacer
const SizedBox(height: 25),
MihForm(
formKey: _formKey,
formFields: [
MihTextFormField(
fillColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
inputColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
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: 25),
// sign in button
Center(
child: MihButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
submitFormInput();
} else {
MihAlertServices().formNotFilledCompletely(context);
}
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"Reset Password",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
],
),
),
),
),
);
}
}

View File

@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.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';
@@ -59,13 +59,9 @@ class _MihSignInState extends State<MihSignIn> {
void submitSignInForm() async {
await signUserIn();
if (successfulSignIn) {
Navigator.of(context).pushNamedAndRemoveUntil(
'/',
(route) => false,
arguments: AuthArguments(
true,
true,
),
context.goNamed(
'mihHome',
extra: true,
);
}
}
@@ -324,8 +320,11 @@ class _MihSignInState extends State<MihSignIn> {
children: [
GestureDetector(
onTap: () {
Navigator.of(context).pushNamed(
'/forgot-password',
// Navigator.of(context).pushNamed(
// '/forgot-password',
// );
context.goNamed(
'forgotPassword',
);
},
child: Text(

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart';
@@ -32,23 +33,14 @@ class _MIHAppDrawerState extends State<MIHAppDrawer> {
}
Widget displayProPic() {
// return MIHProfilePicture(
// profilePictureFile: widget.propicFile,
// proPicController: proPicController,
// proPic: null,
// width: 45,
// radius: 21,
// editable: false,
// onChange: (newProPic) {},
// ),
//print(widget.propicFile);
return GestureDetector(
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
'/mzansi-profile',
arguments:
AppProfileUpdateArguments(widget.signedInUser, widget.propicFile),
context.goNamed(
'mzansiProfileManage',
extra: AppProfileUpdateArguments(
widget.signedInUser,
widget.propicFile,
),
);
},
child: MihCircleAvatar(
@@ -208,10 +200,7 @@ class _MIHAppDrawerState extends State<MIHAppDrawer> {
],
),
onTap: () {
Navigator.of(context).pushNamed(
'/about',
arguments: 1,
);
context.goNamed("aboutMih", extra: 1);
},
),
ListTile(
@@ -241,10 +230,7 @@ class _MIHAppDrawerState extends State<MIHAppDrawer> {
],
),
onTap: () {
Navigator.of(context).pushNamed(
'/about',
arguments: 2,
);
context.goNamed("aboutMih", extra: 2);
},
),
ListTile(
@@ -280,11 +266,15 @@ class _MIHAppDrawerState extends State<MIHAppDrawer> {
});
if (await SuperTokens.doesSessionExist() ==
false) {
Navigator.of(context).pop();
Navigator.of(context).popAndPushNamed(
'/',
arguments: AuthArguments(true, false),
context.goNamed(
'mihHome',
extra: true,
);
// Navigator.of(context).pop();
// Navigator.of(context).popAndPushNamed(
// '/',
// arguments: AuthArguments(true, false),
// );
}
},
),

View File

@@ -1,44 +1,45 @@
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_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_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/business.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_user.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/notification.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/patients.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_env.dart';
import 'package:mzansi_innovation_hub/mih_packages/mih_home/components/mih_app_drawer.dart';
import 'package:mzansi_innovation_hub/mih_packages/mih_home/mih_home_error.dart';
import 'package:mzansi_innovation_hub/mih_packages/mih_home/package_tools/mih_business_home.dart';
import 'package:mzansi_innovation_hub/mih_packages/mih_home/package_tools/mih_personal_home.dart';
import 'package:flutter/material.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_service_calls.dart';
// ignore: must_be_immutable
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;
bool personalSelected;
MihHome({
// 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;
const MihHome({
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.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,
});
@@ -50,6 +51,7 @@ class _MihHomeState extends State<MihHome> {
final proPicController = TextEditingController();
late int _selcetedIndex;
late bool _personalSelected;
late Future<HomeArguments> profileData;
@override
void dispose() {
@@ -59,7 +61,7 @@ class _MihHomeState extends State<MihHome> {
@override
void initState() {
super.initState();
profileData = MIHApiCalls().getProfile(10, context);
if (widget.personalSelected == true) {
setState(() {
_selcetedIndex = 0;
@@ -83,36 +85,60 @@ class _MihHomeState extends State<MihHome> {
@override
Widget build(BuildContext context) {
return MihPackage(
appActionButton: getAction(),
appTools: getTools(),
appBody: getToolBody(),
appToolTitles: getToolTitle(),
actionDrawer: getActionDrawer(),
selectedbodyIndex: _selcetedIndex,
onIndexChange: (newValue) {
if (_selcetedIndex == 0) {
setState(() {
_selcetedIndex = newValue;
_personalSelected = true;
});
return FutureBuilder(
future: profileData,
builder: (context, asyncSnapshot) {
if (asyncSnapshot.connectionState == ConnectionState.waiting) {
return Scaffold(
body: const Mihloadingcircle(
message: "Fetching your Data...",
),
);
} else if (asyncSnapshot.connectionState == ConnectionState.done &&
asyncSnapshot.hasData) {
return MihPackage(
appActionButton: getAction(asyncSnapshot.data!.profilePicUrl),
appTools:
getTools(asyncSnapshot.data!.signedInUser.type != "personal"),
appBody: getToolBody(asyncSnapshot.data!),
appToolTitles: getToolTitle(),
actionDrawer: getActionDrawer(
asyncSnapshot.data!.signedInUser,
asyncSnapshot.data!.profilePicUrl,
),
selectedbodyIndex: _selcetedIndex,
onIndexChange: (newValue) {
if (_selcetedIndex == 0) {
setState(() {
_selcetedIndex = newValue;
_personalSelected = true;
});
} else {
setState(() {
_selcetedIndex = newValue;
_personalSelected = false;
});
}
},
);
} else {
setState(() {
_selcetedIndex = newValue;
_personalSelected = false;
});
return MihHomeError(
errorMessage: asyncSnapshot.hasError
? asyncSnapshot.error.toString()
: "An unknown error occurred",
);
}
},
);
}
Widget getAction() {
Widget getAction(String proPicUrl) {
return Builder(builder: (context) {
return MihPackageAction(
icon: Padding(
padding: const EdgeInsets.only(left: 5.0),
child: MihCircleAvatar(
imageFile: widget.propicFile,
imageFile: proPicUrl != "" ? NetworkImage(proPicUrl) : null,
width: 50,
editable: false,
fileNameController: proPicController,
@@ -147,14 +173,14 @@ class _MihHomeState extends State<MihHome> {
});
}
MIHAppDrawer getActionDrawer() {
MIHAppDrawer getActionDrawer(AppUser signedInUser, String proPicUrl) {
return MIHAppDrawer(
signedInUser: widget.signedInUser,
propicFile: widget.propicFile,
signedInUser: signedInUser,
propicFile: proPicUrl != "" ? NetworkImage(proPicUrl) : null,
);
}
MihPackageTools getTools() {
MihPackageTools getTools(bool isBusinessUser) {
Map<Widget, void Function()?> temp = {};
temp[const Icon(Icons.person)] = () {
setState(() {
@@ -162,7 +188,7 @@ class _MihHomeState extends State<MihHome> {
_personalSelected = true;
});
};
if (widget.isBusinessUser) {
if (isBusinessUser) {
temp[const Icon(Icons.business_center)] = () {
setState(() {
_selcetedIndex = 1;
@@ -176,27 +202,29 @@ class _MihHomeState extends State<MihHome> {
);
}
List<Widget> getToolBody() {
List<Widget> getToolBody(HomeArguments profData) {
List<Widget> toolBodies = [];
toolBodies.add(
MihPersonalHome(
signedInUser: widget.signedInUser,
signedInUser: profData.signedInUser,
personalSelected: _personalSelected,
business: widget.business,
businessUser: widget.businessUser,
propicFile: widget.propicFile,
isUserNew: widget.isUserNew,
isDevActive: widget.isDevActive,
business: profData.business,
businessUser: profData.businessUser,
propicFile: profData.profilePicUrl != ""
? NetworkImage(profData.profilePicUrl)
: null,
isDevActive: AppEnviroment.getEnv() == "Dev",
isUserNew: profData.signedInUser.username == "",
),
);
if (widget.isBusinessUser) {
if (profData.signedInUser.type != "personal") {
toolBodies.add(
MihBusinessHome(
signedInUser: widget.signedInUser,
signedInUser: profData.signedInUser,
personalSelected: _personalSelected,
businessUser: widget.businessUser,
business: widget.business,
isBusinessUserNew: widget.isBusinessUserNew,
businessUser: profData.businessUser,
business: profData.business,
isBusinessUserNew: profData.businessUser == null,
),
);
}

View File

@@ -0,0 +1,150 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.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_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_tool_body.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
class MihHomeError extends StatefulWidget {
final String errorMessage;
const MihHomeError({
super.key,
required this.errorMessage,
});
@override
State<MihHomeError> createState() => _MihHomeErrorState();
}
class _MihHomeErrorState extends State<MihHomeError> {
int _selcetedIndex = 0;
@override
Widget build(BuildContext context) {
return MihPackage(
appActionButton: getErrorAction(),
appTools: getErrorTools(),
appBody: getErrorToolBody(widget.errorMessage),
selectedbodyIndex: _selcetedIndex,
onIndexChange: (newValue) {
setState(() {
_selcetedIndex = newValue;
});
//print("Index: $_selcetedIndex");
},
);
}
MihPackageAction getErrorAction() {
return MihPackageAction(
icon: const Icon(Icons.refresh),
iconSize: 35,
onTap: () {
context.goNamed(
'mihHome',
extra: true,
);
},
);
}
MihPackageTools getErrorTools() {
Map<Widget, void Function()?> temp = {};
temp[const Icon(Icons.power_off_outlined)] = () {
setState(() {
_selcetedIndex = 0;
});
};
return MihPackageTools(
tools: temp,
selcetedIndex: _selcetedIndex,
);
}
List<Widget> getErrorToolBody(String error) {
List<Widget> toolBodies = [
MihPackageToolBody(
borderOn: true,
bodyItem: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Connection Error",
textAlign: TextAlign.center,
style: TextStyle(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 35,
fontWeight: FontWeight.bold,
),
),
Icon(
Icons.power_off_outlined,
size: 150,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
SizedBox(
width: 500,
child: Text(
"Looks like we ran into an issue getting your data.\nPlease check you internet connection and try again.",
textAlign: TextAlign.center,
style: TextStyle(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 15),
MihButton(
onPressed: () {
context.goNamed(
'mihHome',
extra: true,
);
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
width: 300,
child: Text(
"Refresh",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 15),
Padding(
padding: const EdgeInsets.all(10.0),
child: SizedBox(
width: 500,
child: SelectionArea(
child: Text(
"Error: $error",
textAlign: TextAlign.left,
style: TextStyle(
color: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
),
),
],
),
)
];
return toolBodies;
}
}

View File

@@ -75,7 +75,6 @@ class _MIHProfileGetterState extends State<MIHProfileGetter> {
_selcetedIndex = 0;
});
};
return MihPackageTools(
tools: temp,
selcetedIndex: _selcetedIndex,
@@ -244,18 +243,18 @@ class _MIHProfileGetterState extends State<MIHProfileGetter> {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
return MihHome(
signedInUser: snapshot.requireData.signedInUser,
businessUser: snapshot.data!.businessUser,
business: snapshot.data!.business,
patient: snapshot.data!.patient,
notifications: snapshot.data!.notifi,
propicFile: snapshot.data!.profilePicUrl != ""
? NetworkImage(snapshot.data!.profilePicUrl)
: null,
isUserNew: isUserNew(snapshot.requireData.signedInUser),
isBusinessUser: isBusinessUser(snapshot.requireData.signedInUser),
isBusinessUserNew: isBusinessUserNew(snapshot.data!.businessUser),
isDevActive: isDevActive(),
// signedInUser: snapshot.requireData.signedInUser,
// businessUser: snapshot.data!.businessUser,
// business: snapshot.data!.business,
// patient: snapshot.data!.patient,
// notifications: snapshot.data!.notifi,
// propicFile: snapshot.data!.profilePicUrl != ""
// ? NetworkImage(snapshot.data!.profilePicUrl)
// : null,
// isUserNew: isUserNew(snapshot.requireData.signedInUser),
// isBusinessUser: isBusinessUser(snapshot.requireData.signedInUser),
// isBusinessUserNew: isBusinessUserNew(snapshot.data!.businessUser),
// isDevActive: isDevActive(),
personalSelected: widget.personalSelected,
);
// return MIHHomeLegacy(

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.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_icons.dart';
@@ -244,15 +245,24 @@ class _MihBusinessHomeState extends State<MihBusinessHome>
hintColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
onPrefixIconTap: () {
Navigator.of(context).pushNamed(
'/mzansi-ai',
arguments: MzansiAiArguments(
context.goNamed(
"mzansiAi",
extra: MzansiAiArguments(
widget.signedInUser,
searchController.text.isEmpty
? null
: searchController.text,
),
);
// Navigator.of(context).pushNamed(
// '/mzansi-ai',
// arguments: MzansiAiArguments(
// widget.signedInUser,
// searchController.text.isEmpty
// ? null
// : searchController.text,
// ),
// );
searchController.clear();
},
searchFocusNode: _searchFocusNode,

View File

@@ -1,8 +1,9 @@
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/Example/package_tiles/test_package_tile.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_icons.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_package_tile.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
@@ -159,27 +160,10 @@ class _MihPersonalHomeState extends State<MihPersonalHome>
//=============== Dev ===============
if (widget.isDevActive) {
temp.add({
"test": MihPackageTile(
onTap: () {
Navigator.of(context).pushNamed(
'/package-dev',
arguments: TestArguments(
widget.signedInUser,
widget.business,
),
);
},
appName: "Test",
appIcon: Icon(
Icons.warning_amber_rounded,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
iconSize: packageSize,
primaryColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
secondaryColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
"test": TestPackageTile(
signedInUser: widget.signedInUser,
business: widget.business,
packageSize: packageSize,
)
});
}
@@ -219,9 +203,9 @@ class _MihPersonalHomeState extends State<MihPersonalHome>
void autoNavToProfile() {
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).pushNamed(
'/mzansi-profile',
arguments: AppProfileUpdateArguments(
context.goNamed(
'mzansiProfileManage',
extra: AppProfileUpdateArguments(
widget.signedInUser,
widget.propicFile,
),
@@ -299,15 +283,24 @@ class _MihPersonalHomeState extends State<MihPersonalHome>
hintColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
onPrefixIconTap: () {
Navigator.of(context).pushNamed(
'/mzansi-ai',
arguments: MzansiAiArguments(
context.goNamed(
"mzansiAi",
extra: MzansiAiArguments(
widget.signedInUser,
searchController.text.isEmpty
? null
: searchController.text,
),
);
// Navigator.of(context).pushNamed(
// '/mzansi-ai',
// arguments: MzansiAiArguments(
// widget.signedInUser,
// searchController.text.isEmpty
// ? null
// : searchController.text,
// ),
// );
searchController.clear();
},
searchFocusNode: _searchFocusNode,

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.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';
@@ -28,7 +29,10 @@ class _MzansiAiState extends State<MzansiAi> {
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
Navigator.of(context).pop();
context.goNamed(
'mihHome',
extra: true,
);
FocusScope.of(context).unfocus();
},
);

View File

@@ -1,3 +1,4 @@
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart';
@@ -25,13 +26,20 @@ class _MzansiAiTileState extends State<MzansiAiTile> {
Widget build(BuildContext context) {
return MihPackageTile(
onTap: () {
Navigator.of(context).pushNamed(
'/mzansi-ai',
arguments: MzansiAiArguments(
context.goNamed(
'mzansiAi',
extra: MzansiAiArguments(
widget.signedInUser,
"",
),
);
// Navigator.of(context).pushNamed(
// '/mzansi-ai',
// arguments: MzansiAiArguments(
// widget.signedInUser,
// "",
// ),
// );
},
appName: "Mzansi AI",
appIcon: Icon(

Some files were not shown because too many files have changed in this diff Show More