From 59b5b09048c84e429cfc744d6e66de1119bbaa2c Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 23 Apr 2025 19:31:56 +0200 Subject: [PATCH 01/22] new circle avitar --- .../mih_circle_avatar.dart | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart diff --git a/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart b/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart new file mode 100644 index 00000000..14701211 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart @@ -0,0 +1,124 @@ +import 'dart:io'; + +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'; + +class MihCircleAvatar extends StatefulWidget { + final ImageProvider? imageFile; + final double width; + final bool editable; + final TextEditingController fileNameController; + final onChange; + const MihCircleAvatar({ + super.key, + required this.imageFile, + required this.width, + required this.editable, + required this.fileNameController, + required this.onChange, + }); + + @override + State createState() => _MihCircleAvatarState(); +} + +class _MihCircleAvatarState extends State { + late ImageProvider? imagePreview; + + @override + void initState() { + super.initState(); + setState(() { + imagePreview = widget.imageFile; + }); + } + + @override + Widget build(BuildContext context) { + return Container( + width: widget.width, + height: widget.width, + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.all(6.0), + child: CircleAvatar( + radius: widget.width / 2, + backgroundColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + backgroundImage: imagePreview, + ), + ), + Icon( + size: widget.width, + MihIcons.mihCircleFrame, + color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + ), + Visibility( + visible: widget.editable, + child: Positioned( + bottom: 0, + right: 0, + child: IconButton.filled( + onPressed: () async { + try { + FilePickerResult? result = + await FilePicker.platform.pickFiles( + type: FileType.image, + ); + // print("Here 1"); + if (MzanziInnovationHub.of(context)!.theme.getPlatform() == + "Web") { + // print("Here 2"); + if (result == null) return; + // print("Here 3"); + PlatformFile? selectedFile = result.files.first; + setState(() { + // print("Here 4"); + widget.onChange(MemoryImage(selectedFile.bytes!)); + // print("Here 5"); + imagePreview = MemoryImage(selectedFile.bytes!); + }); + + setState(() { + widget.fileNameController.text = selectedFile.name; + }); + } else { + if (result != null) { + File file = File(result.files.single.path!); + PlatformFile? androidFile = PlatformFile( + path: file.path, + name: file.path.split('/').last, + size: file.lengthSync(), + bytes: await file.readAsBytes(), // Read file bytes + //extension: fileExtension, + ); + setState(() { + widget.onChange(MemoryImage(androidFile.bytes!)); + imagePreview = FileImage(file); + }); + + setState(() { + widget.fileNameController.text = + file.path.split('/').last; + }); + } else { + print("here in else"); + // User canceled the picker + } + } + } catch (e) { + print("Error: $e"); + } + }, + icon: const Icon(Icons.edit), + ), + ), + ), + ], + ), + ); + } +} From b55ee83c6edc7b63726c2203abda5ece19c5e071 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 23 Apr 2025 19:32:11 +0200 Subject: [PATCH 02/22] new file api class --- Frontend/lib/mih_apis/mih_file_api.dart | 143 ++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 Frontend/lib/mih_apis/mih_file_api.dart diff --git a/Frontend/lib/mih_apis/mih_file_api.dart b/Frontend/lib/mih_apis/mih_file_api.dart new file mode 100644 index 00000000..1823d987 --- /dev/null +++ b/Frontend/lib/mih_apis/mih_file_api.dart @@ -0,0 +1,143 @@ +import 'dart:convert'; + +import 'package:file_picker/file_picker.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_components/mih_pop_up_messages/mih_success_message.dart'; +import 'package:mzansi_innovation_hub/mih_env/env.dart'; +import 'package:flutter/material.dart'; +import 'package:supertokens_flutter/http.dart' as http; +import 'package:http/http.dart' as http2; +import 'package:supertokens_flutter/supertokens.dart'; + +class MihFileApi { + final baseAPI = AppEnviroment.baseApiUrl; + + static Future getMinioFileUrl( + String filePath, + BuildContext context, + ) async { + // loadingPopUp(context); + // print("here"); + // var url = + // "${AppEnviroment.baseApiUrl}/minio/pull/file/${AppEnviroment.getEnv()}/$filePath"; + // var response = await http.get(Uri.parse(url)); + String fileUrl = ""; + // print(response.statusCode); + // if (response.statusCode == 200) { + // String body = response.body; + // var decodedData = jsonDecode(body); + + // fileUrl = decodedData['minioURL']; + // } else { + // fileUrl = ""; + // } + // Navigator.of(context).pop(); // Pop loading dialog + // return fileUrl; + try { + var url = + "${AppEnviroment.baseApiUrl}/minio/pull/file/${AppEnviroment.getEnv()}/$filePath"; + var response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + var decodedData = jsonDecode(response.body); + fileUrl = decodedData['minioURL']; + } else { + internetConnectionPopUp(context); + } + } catch (e) { + internetConnectionPopUp(context); + } finally { + // Navigator.of(context).pop(); // Always pop loading dialog + } + return fileUrl; + } + + static Future uploadFile( + String app_id, + String folderName, + PlatformFile? file, + BuildContext context, + ) async { + loadingPopUp(context); + var token = await SuperTokens.getAccessToken(); + var request = http2.MultipartRequest( + 'POST', Uri.parse("${AppEnviroment.baseApiUrl}/minio/upload/file/")); + request.headers['accept'] = 'application/json'; + request.headers['Authorization'] = 'Bearer $token'; + request.headers['Content-Type'] = 'multipart/form-data'; + request.fields['app_id'] = app_id; + request.fields['folder'] = folderName; + request.files.add(await http2.MultipartFile.fromBytes('file', file!.bytes!, + filename: file.name.replaceAll(RegExp(r' '), '-'))); + var response = await request.send(); + Navigator.of(context).pop(); // Pop loading dialog + return response.statusCode; + } + + static Future deleteFile( + String app_id, + String folderName, + String fileName, + BuildContext context, + ) async { + loadingPopUp(context); + var fname = fileName.replaceAll(RegExp(r' '), '-'); + var filePath = "$app_id/$folderName/$fname"; + var response = await http.delete( + Uri.parse("${AppEnviroment.baseApiUrl}/minio/delete/file/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({"file_path": filePath}), + ); + Navigator.of(context).pop(); // Pop loading dialog + return response.statusCode; + } + + // Future signOut() async { + // await SuperTokens.signOut(completionHandler: (error) { + // print(error); + // }); + // if (await SuperTokens.doesSessionExist() == false) { + // Navigator.of(context).pop(); + // Navigator.of(context).popAndPushNamed( + // '/', + // arguments: AuthArguments(true, false), + // ); + // } + // } + +//================== POP UPS ========================================================================== + + static void internetConnectionPopUp(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage( + errorType: "Internet Connection", + ); + }, + ); + } + + static void successPopUp(String message, BuildContext context) { + showDialog( + context: context, + builder: (context) { + return MIHSuccessMessage( + successType: "Success", + successMessage: message, + ); + }, + ); + } + + static void loadingPopUp(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle(); + }, + ); + } +} From df52ef373b0b661c15579c87a5f481524ce6673d Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 23 Apr 2025 19:50:33 +0200 Subject: [PATCH 03/22] test new circle avatar --- .../test/package_tools/package_tool_one.dart | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_one.dart b/Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_one.dart index bcaea3fb..804193b9 100644 --- a/Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_one.dart +++ b/Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_one.dart @@ -1,9 +1,12 @@ +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih-app_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; @@ -15,6 +18,9 @@ class PackageToolOne extends StatefulWidget { } class _PackageToolOneState extends State { + late ImageProvider? imagePreview; + PlatformFile? file; + TextEditingController _fileNameController = TextEditingController(); void showTestFullWindow() { showDialog( context: context, @@ -49,6 +55,15 @@ class _PackageToolOneState extends State { ); } + @override + void initState() { + super.initState(); + setState(() { + imagePreview = const NetworkImage( + "https://lh3.googleusercontent.com/nW4ZZ89Q1ATz7Ht3nsAVWXL_cwNi4gNusqQZiL60UuuI3FG-VM7bTYDoJ-sUr2kDTdorfQYjxo5PjDM-0MO5rA=s512"); + }); + } + @override Widget build(BuildContext context) { return MihAppToolBody( @@ -97,6 +112,26 @@ class _PackageToolOneState extends State { MzanziInnovationHub.of(context)!.theme.primaryColor(), ), ), + ), + const SizedBox(height: 10), + MihCircleAvatar( + imageFile: imagePreview, + width: 150, + editable: true, + fileNameController: _fileNameController, + userSelectedfile: file, + onChange: (selectedImage) { + setState(() { + file = selectedImage; + }); + }, + ), + const SizedBox(height: 10), + MIHTextField( + controller: _fileNameController, + hintText: "Selected File", + editable: false, + required: false, ) ], ), From 260b1a1feb09aa05248ad9c9511bc7516e288013 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 23 Apr 2025 20:04:41 +0200 Subject: [PATCH 04/22] correct sizing --- .../mih_circle_avatar.dart | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart b/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart index 14701211..61674c4c 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_circle_avatar.dart @@ -11,12 +11,16 @@ class MihCircleAvatar extends StatefulWidget { final bool editable; final TextEditingController fileNameController; final onChange; + final PlatformFile? userSelectedfile; + final Color frameColor; const MihCircleAvatar({ super.key, required this.imageFile, required this.width, required this.editable, required this.fileNameController, + required this.userSelectedfile, + required this.frameColor, required this.onChange, }); @@ -38,23 +42,25 @@ class _MihCircleAvatarState extends State { @override Widget build(BuildContext context) { return Container( + // color: Colors.white, + alignment: Alignment.center, width: widget.width, height: widget.width, child: Stack( + alignment: Alignment.center, children: [ - Padding( - padding: const EdgeInsets.all(6.0), - child: CircleAvatar( - radius: widget.width / 2, - backgroundColor: - MzanziInnovationHub.of(context)!.theme.primaryColor(), - backgroundImage: imagePreview, - ), + CircleAvatar( + radius: widget.width / 2.2, + backgroundColor: widget.frameColor, + backgroundImage: imagePreview, ), - Icon( - size: widget.width, - MihIcons.mihCircleFrame, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + FittedBox( + fit: BoxFit.fill, + child: Icon( + size: widget.width, + MihIcons.mihCircleFrame, + color: widget.frameColor, + ), ), Visibility( visible: widget.editable, @@ -77,7 +83,7 @@ class _MihCircleAvatarState extends State { PlatformFile? selectedFile = result.files.first; setState(() { // print("Here 4"); - widget.onChange(MemoryImage(selectedFile.bytes!)); + widget.onChange(selectedFile); // print("Here 5"); imagePreview = MemoryImage(selectedFile.bytes!); }); @@ -96,7 +102,7 @@ class _MihCircleAvatarState extends State { //extension: fileExtension, ); setState(() { - widget.onChange(MemoryImage(androidFile.bytes!)); + widget.onChange(androidFile); imagePreview = FileImage(file); }); From c8ad5c5c5b06c1be0d058826ffc4e5c2c057a0c4 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 23 Apr 2025 20:08:02 +0200 Subject: [PATCH 05/22] tester --- .../test/package_tools/package_tool_one.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_one.dart b/Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_one.dart index 804193b9..5d09fd24 100644 --- a/Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_one.dart +++ b/Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_one.dart @@ -116,10 +116,12 @@ class _PackageToolOneState extends State { const SizedBox(height: 10), MihCircleAvatar( imageFile: imagePreview, - width: 150, - editable: true, + width: 50, + editable: false, fileNameController: _fileNameController, userSelectedfile: file, + frameColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), onChange: (selectedImage) { setState(() { file = selectedImage; From cae07181b8b5b2d52a7272c10f38e41deffe2684 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 23 Apr 2025 20:08:28 +0200 Subject: [PATCH 06/22] use enw circle avatar --- .../mih_home/components/mih_app_drawer.dart | 25 +++-- .../lib/mih_packages/mih_home/mih_home.dart | 28 ++++-- .../package_tools/mih_personal_profile.dart | 92 ++++++++----------- 3 files changed, 72 insertions(+), 73 deletions(-) diff --git a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart index df0f1845..a7c92dd5 100644 --- a/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart +++ b/Frontend/lib/mih_packages/mih_home/components/mih_app_drawer.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; import '../../../main.dart'; import '../../../mih_objects/app_user.dart'; import '../../../mih_objects/arguments.dart'; import 'package:supertokens_flutter/supertokens.dart'; -import '../../../mih_components/mih_profile_picture.dart'; class MIHAppDrawer extends StatefulWidget { final AppUser signedInUser; @@ -53,17 +53,26 @@ class _MIHAppDrawerState extends State { widget.signedInUser, widget.propicFile), ); }, - child: MIHProfilePicture( - profilePictureFile: widget.propicFile, - proPicController: proPicController, - proPic: null, + child: MihCircleAvatar( + imageFile: widget.propicFile, width: 60, - radius: 27, - drawerMode: true, editable: false, + fileNameController: proPicController, + onChange: (_) {}, + userSelectedfile: null, frameColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - onChange: (newProPic) {}, ), + // MIHProfilePicture( + // profilePictureFile: widget.propicFile, + // proPicController: proPicController, + // proPic: null, + // width: 60, + // radius: 27, + // drawerMode: true, + // editable: false, + // frameColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + // onChange: (newProPic) {}, + // ), // Stack( // alignment: Alignment.center, diff --git a/Frontend/lib/mih_packages/mih_home/mih_home.dart b/Frontend/lib/mih_packages/mih_home/mih_home.dart index aeb6e56b..b4628fdd 100644 --- a/Frontend/lib/mih_packages/mih_home/mih_home.dart +++ b/Frontend/lib/mih_packages/mih_home/mih_home.dart @@ -2,7 +2,7 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_tools.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_profile_picture.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/business.dart'; import 'package:mzansi_innovation_hub/mih_objects/business_user.dart'; @@ -101,17 +101,27 @@ class _MihHomeState extends State { return MihAppAction( icon: Padding( padding: const EdgeInsets.only(left: 5.0), - child: MIHProfilePicture( - profilePictureFile: widget.propicFile, - proPicController: proPicController, - proPic: null, - width: 45, - radius: 21, - drawerMode: false, + child: MihCircleAvatar( + imageFile: widget.propicFile, + width: 50, editable: false, + fileNameController: proPicController, + userSelectedfile: null, + // frameColor: frameColor, frameColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - onChange: (newProPic) {}, + onChange: (_) {}, ), + // MIHProfilePicture( + // profilePictureFile: widget.propicFile, + // proPicController: proPicController, + // proPic: null, + // width: 45, + // radius: 21, + // drawerMode: false, + // editable: false, + // frameColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + // onChange: (newProPic) {}, + // ), ), iconSize: 45, onTap: () { diff --git a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart index 82a8ea2d..ae7a9eac 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart @@ -1,22 +1,20 @@ import 'dart:convert'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_file_api.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_file_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih-app_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.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_components/mih_pop_up_messages/mih_success_message.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_profile_picture.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; -import 'package:supertokens_flutter/supertokens.dart'; import 'package:supertokens_flutter/http.dart' as http; -import 'package:http/http.dart' as http2; class MihPersonalProfile extends StatefulWidget { final AppProfileUpdateArguments arguments; @@ -82,33 +80,14 @@ class _MihPersonalProfileState extends State { } Future uploadSelectedFile(PlatformFile? file) async { - //print("MIH Profile Picture: $file"); - //var strem = new http.ByteStream.fromBytes(file.bytes.) - //start loading circle - showDialog( - context: context, - builder: (context) { - return const Mihloadingcircle(); - }, + var response = await MihFileApi.uploadFile( + widget.arguments.signedInUser.app_id, + "profile_files", + file, + context, ); - var token = await SuperTokens.getAccessToken(); - var request = http2.MultipartRequest( - 'POST', Uri.parse("${AppEnviroment.baseApiUrl}/minio/upload/file/")); - request.headers['accept'] = 'application/json'; - request.headers['Authorization'] = 'Bearer $token'; - request.headers['Content-Type'] = 'multipart/form-data'; - request.fields['app_id'] = widget.arguments.signedInUser.app_id; - request.fields['folder'] = "profile_files"; - request.files.add(await http2.MultipartFile.fromBytes('file', file!.bytes!, - filename: file.name.replaceAll(RegExp(r' '), '-'))); - var response1 = await request.send(); - if (response1.statusCode == 200) { + if (response == 200) { deleteFileApiCall(oldProPicName); - // end loading circle - //Navigator.of(context).pop(); - // String message = - // "The file ${file.name.replaceAll(RegExp(r' '), '-')} has been successfully generated and added to ${widget.signedInUser.fname} ${widget.signedInUser.lname}'s record. You can now access and download it for their use."; - // successPopUp(message); } else { internetConnectionPopUp(); } @@ -153,11 +132,6 @@ class _MihPersonalProfileState extends State { false, ), ); - // Navigator.of(context).pushNamed( - // '/mzansi-profile', - // arguments: AppProfileUpdateArguments( - // widget.arguments.signedInUser, widget.arguments.propicFile), - // ); String message = "${widget.arguments.signedInUser.email}'s information has been updated successfully!"; successPopUp(message); @@ -168,20 +142,13 @@ class _MihPersonalProfileState extends State { } Future deleteFileApiCall(String filename) async { - // delete file from minio - var fname = filename.replaceAll(RegExp(r' '), '-'); - var filePath = - "${widget.arguments.signedInUser.app_id}/profile_files/$fname"; - var response = await http.delete( - Uri.parse("${AppEnviroment.baseApiUrl}/minio/delete/file/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({"file_path": filePath}), + var response = await MihFileApi.deleteFile( + widget.arguments.signedInUser.app_id, + "profile_files", + filename, + context, ); - //print("Here4"); - //print(response.statusCode); - if (response.statusCode == 200) { + if (response == 200) { //SQL delete } else { internetConnectionPopUp(); @@ -258,21 +225,34 @@ class _MihPersonalProfileState extends State { child: Column( children: [ //displayProPic(), - MIHProfilePicture( - profilePictureFile: widget.arguments.propicFile, - proPicController: proPicController, - proPic: proPic, - width: 155, - radius: 70, - drawerMode: false, + MihCircleAvatar( + imageFile: propicPreview, + width: 150, editable: true, + fileNameController: proPicController, + userSelectedfile: proPic, frameColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - onChange: (newProPic) { + onChange: (selectedImage) { setState(() { - proPic = newProPic; + proPic = selectedImage; }); }, ), + // MIHProfilePicture( + // profilePictureFile: widget.arguments.propicFile, + // proPicController: proPicController, + // proPic: proPic, + // width: 155, + // radius: 70, + // drawerMode: false, + // editable: true, + // frameColor: MzanziInnovationHub.of(context)!.theme.secondaryColor(), + // onChange: (newProPic) { + // setState(() { + // proPic = newProPic; + // }); + // }, + // ), const SizedBox(height: 25.0), Visibility( visible: false, From ef6027f45f96dc85519282c320063f03c92c2cf3 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 23 Apr 2025 20:09:13 +0200 Subject: [PATCH 07/22] add context --- Frontend/lib/mih_packages/mih_home/mih_profile_getter.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/lib/mih_packages/mih_home/mih_profile_getter.dart b/Frontend/lib/mih_packages/mih_home/mih_profile_getter.dart index 2ed53067..95fb57c2 100644 --- a/Frontend/lib/mih_packages/mih_home/mih_profile_getter.dart +++ b/Frontend/lib/mih_packages/mih_home/mih_profile_getter.dart @@ -232,7 +232,7 @@ class _MIHProfileGetterState extends State { @override void initState() { //profile = getProfile(); - profile = MIHApiCalls().getProfile(amount); + profile = MIHApiCalls().getProfile(amount, context); super.initState(); } From 175ad9b0c94c359e8c35ecc0a08b65fff7babb93 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 09:32:28 +0200 Subject: [PATCH 08/22] add context --- Frontend/lib/mih_apis/mih_api_calls.dart | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/Frontend/lib/mih_apis/mih_api_calls.dart b/Frontend/lib/mih_apis/mih_api_calls.dart index 071004f8..c3e61326 100644 --- a/Frontend/lib/mih_apis/mih_api_calls.dart +++ b/Frontend/lib/mih_apis/mih_api_calls.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:mzansi_innovation_hub/mih_apis/mih_file_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_notification_apis.dart'; import 'package:flutter/material.dart'; // import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; @@ -43,7 +44,10 @@ class MIHApiCalls { /// - Business User details. /// - notifications. /// - user profile picture. - Future getProfile(int notificationAmount) async { + Future getProfile( + int notificationAmount, + BuildContext context, + ) async { AppUser userData; Business? busData; BusinessUser? bUserData; @@ -98,20 +102,8 @@ class MIHApiCalls { // userPic = "${AppEnviroment.baseFileUrl}/mih/${userData.pro_pic_path}"; // } else { - var url = - "${AppEnviroment.baseApiUrl}/minio/pull/file/${AppEnviroment.getEnv()}/${userData.pro_pic_path}"; - var response = await http.get(Uri.parse(url)); - - if (response.statusCode == 200) { - String body = response.body; - var decodedData = jsonDecode(body); - - userPic = decodedData['minioURL']; - } else { - userPic = ""; - // throw Exception( - // "Error: GetUserData status code ${response.statusCode}"); - } + userPic = + await MihFileApi.getMinioFileUrl(userData.pro_pic_path, context); } //Get Notifications From acf761c9ea90f1b0342ed46bdbec17efd1bd4352 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 10:34:38 +0200 Subject: [PATCH 09/22] new business details tool and apis --- .../mih_apis/mih_business_details_apis.dart | 79 ++++ .../package_tools/mih_business_details.dart | 426 ++++++++++++++++++ 2 files changed, 505 insertions(+) create mode 100644 Frontend/lib/mih_apis/mih_business_details_apis.dart create mode 100644 Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart diff --git a/Frontend/lib/mih_apis/mih_business_details_apis.dart b/Frontend/lib/mih_apis/mih_business_details_apis.dart new file mode 100644 index 00000000..38aa50a4 --- /dev/null +++ b/Frontend/lib/mih_apis/mih_business_details_apis.dart @@ -0,0 +1,79 @@ +import 'dart:convert'; + +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:flutter/material.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:mzansi_innovation_hub/mih_env/env.dart'; +import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:supertokens_flutter/http.dart' as http; + +class MihBusinessDetailsApi { + final LocationSettings locationSettings = const LocationSettings( + accuracy: LocationAccuracy.high, + distanceFilter: 100, + ); + + ///This function is to get the current location of the signed in user. + ///First checks the permission, if permission is denied (new user), request permission from user. + ///if user has blocked permission (denied or denied forver), user will get error pop up. + ///if user has granted permission (while in use), function will return Position object. + Future updateBusinessDetails( + String business_id, + String business_name, + String business_type, + String business_registration_no, + String business_practice_no, + String business_vat_no, + String business_email, + String business_phone_number, + String business_location, + String business_logo_name, + BuildContext context, + ) async { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle(); + }, + ); + print("Here 1"); + var response = await http.put( + Uri.parse("${AppEnviroment.baseApiUrl}/business/update/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "business_id": business_id, + "Name": business_name, + "type": business_type, + "registration_no": business_registration_no, + "logo_name": business_logo_name, + "logo_path": "$business_id/business_files/$business_logo_name", + "contact_no": business_phone_number, + "bus_email": business_email, + "gps_location": business_location, + "practice_no": business_practice_no, + "vat_no": business_vat_no, + }), + ); + print("Here 2"); + Navigator.of(context).pop(); + if (response.statusCode == 200) { + print("Here 3"); + return 200; + } else { + print("Here 4"); + internetConnectionPopUp(context); + return 500; + } + } + + void internetConnectionPopUp(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Internet Connection"); + }, + ); + } +} diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart new file mode 100644 index 00000000..d620acc7 --- /dev/null +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart @@ -0,0 +1,426 @@ +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_apis/mih_business_details_apis.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_file_api.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_location_api.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih-app_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.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_components/mih_pop_up_messages/mih_success_message.dart'; +import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; + +class MihBusinessDetails extends StatefulWidget { + final BusinessArguments arguments; + const MihBusinessDetails({ + super.key, + required this.arguments, + }); + + @override + State createState() => _MihBusinessDetailsState(); +} + +class _MihBusinessDetailsState extends State { + late Future fileUrlFuture; + PlatformFile? imageFile; + final fileNameController = TextEditingController(); + final regController = TextEditingController(); + final nameController = TextEditingController(); + final typeController = TextEditingController(); + final practiceNoController = TextEditingController(); + final vatNoController = TextEditingController(); + final contactController = TextEditingController(); + final emailController = TextEditingController(); + final locationController = TextEditingController(); + + Future submitForm() async { + if (!isEmailValid()) { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Invalid Email"); + }, + ); + } else if (isFormFilled()) { + int statusCode = 0; + statusCode = await MihBusinessDetailsApi().updateBusinessDetails( + widget.arguments.business!.business_id, + nameController.text, + typeController.text, + regController.text, + practiceNoController.text, + vatNoController.text, + emailController.text, + contactController.text, + locationController.text, + fileNameController.text, + context, + ); + if (statusCode == 200) { + bool successfullyUploadedFile = await uploadFile(); + if (successfullyUploadedFile) { + Navigator.of(context).pop(); + Navigator.of(context).pop(); + Navigator.of(context).pushNamed( + '/', + arguments: AuthArguments( + false, + false, + ), + ); + // File uploaded successfully + showDialog( + context: context, + builder: (context) { + return const MIHSuccessMessage( + successType: "Success", + successMessage: "Business details updated successfully", + ); + }, + ); + } else { + // File upload failed + showDialog( + context: context, + builder: (context) { + return MihAppAlert( + alertIcon: Icon( + Icons.warning_rounded, + color: MzanziInnovationHub.of(context)!.theme.errorColor(), + ), + alertTitle: "Error Updating Business Details", + alertBody: Column( + children: [ + Text( + "Hi there! To jump into the MIH Home Package, you'll need to set up biometric authentication (like fingerprint or face ID) on your device first. It looks like it's not quite ready yet.\n\nPlease head over to your device's settings to enable it, or press the button below to start the set up process now.", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + ), + ), + ], + ), + alertColour: + MzanziInnovationHub.of(context)!.theme.errorColor(), + ); + }, + ); + } + } else { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Error"); + }, + ); + } + } else { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Input Error"); + }, + ); + } + } + + Future uploadFile() async { + if (imageFile != null) { + int uploadStatusCode = 0; + uploadStatusCode = await MihFileApi.uploadFile( + widget.arguments.business!.business_id, + "business_files", + imageFile!, + context, + ); + if (uploadStatusCode == 200) { + int deleteStatusCode = 0; + deleteStatusCode = await MihFileApi.deleteFile( + widget.arguments.business!.logo_path.split("/").first, + "business_files", + widget.arguments.business!.logo_path.split("/").last, + context, + ); + if (deleteStatusCode == 200) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return true; // No file selected, so no upload needed + } + } + + bool isFileSelected() { + if (imageFile != null) { + return true; + } else { + return false; + } + } + + bool isEmailValid() { + String text = emailController.text; + var regex = RegExp(r'^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$'); + return regex.hasMatch(text); + } + + bool isFormFilled() { + if (regController.text.isEmpty || + nameController.text.isEmpty || + typeController.text.isEmpty || + practiceNoController.text.isEmpty || + vatNoController.text.isEmpty || + contactController.text.isEmpty || + emailController.text.isEmpty || + locationController.text.isEmpty) { + return false; + } else { + return true; + } + } + + @override + void dispose() { + super.dispose(); + fileNameController.dispose(); + regController.dispose(); + nameController.dispose(); + typeController.dispose(); + practiceNoController.dispose(); + vatNoController.dispose(); + contactController.dispose(); + emailController.dispose(); + locationController.dispose(); + imageFile = null; + } + + @override + void initState() { + super.initState(); + setState(() { + fileNameController.text = + widget.arguments.business!.logo_path.split("/").last; + regController.text = widget.arguments.business!.registration_no; + nameController.text = widget.arguments.business!.Name; + typeController.text = widget.arguments.business!.type; + practiceNoController.text = widget.arguments.business!.practice_no; + vatNoController.text = widget.arguments.business!.vat_no; + contactController.text = widget.arguments.business!.contact_no; + emailController.text = widget.arguments.business!.bus_email; + locationController.text = widget.arguments.business!.gps_location; + }); + fileUrlFuture = MihFileApi.getMinioFileUrl( + widget.arguments.business!.logo_path, + context, + ); + } + + @override + Widget build(BuildContext context) { + return MihAppToolBody( + borderOn: true, + bodyItem: getBody(context), + ); + } + + Widget getBody(BuildContext context) { + return MihSingleChildScroll( + child: Column( + children: [ + const Text( + "Business Details", + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 20), + FutureBuilder( + future: fileUrlFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: Mihloadingcircle()); + } else if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData && + snapshot.data != null && + snapshot.data.toString().isNotEmpty) { + return MihCircleAvatar( + imageFile: NetworkImage(snapshot.data.toString()), + width: 150, + editable: true, + fileNameController: fileNameController, + userSelectedfile: imageFile, + frameColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + onChange: (selectedfile) { + setState(() { + imageFile = selectedfile; + }); + }, + ); + // MIHProfilePicture( + // profilePictureFile: NetworkImage(snapshot.data.toString()), + // proPicController: TextEditingController(), + // proPic: null, + // width: 100, + // radius: 50, + // drawerMode: false, + // editable: false, + // onChange: () {}, + // frameColor: Colors.white, + // ); + } else if (snapshot.hasError) { + return Text("Error: ${snapshot.error}"); + } else { + return const Text("Error loading image"); + } + }), + Visibility( + visible: true, + child: MIHTextField( + controller: fileNameController, + hintText: "Selected File Name", + editable: false, + required: false, + ), + ), + const SizedBox(height: 20), + MIHTextField( + controller: regController, + hintText: "Registration No.", + editable: true, + required: true, + ), + const SizedBox(height: 10), + MIHTextField( + controller: nameController, + hintText: "Business Name", + editable: true, + required: true, + ), + const SizedBox(height: 10), + MIHTextField( + controller: typeController, + hintText: "Business Type", + editable: true, + required: true, + ), + const SizedBox(height: 10), + MIHTextField( + controller: practiceNoController, + hintText: "Practice Number", + editable: true, + required: true, + ), + const SizedBox(height: 10), + MIHTextField( + controller: vatNoController, + hintText: "VAT Number", + editable: true, + required: true, + ), + const SizedBox(height: 10), + MIHTextField( + controller: contactController, + hintText: "Contact Number", + editable: true, + required: true, + ), + const SizedBox(height: 10), + MIHTextField( + controller: emailController, + hintText: "Email", + editable: true, + required: true, + ), + const SizedBox(height: 10), + Row( + children: [ + Flexible( + child: MIHTextField( + controller: locationController, + hintText: "Location", + editable: false, + required: false, + ), + ), + const SizedBox(width: 10.0), + SizedBox( + width: 100.0, + height: 50.0, + child: MIHButton( + buttonText: "Set", + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + textColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + onTap: () { + MIHLocationAPI().getGPSPosition(context).then((position) { + if (position != null) { + setState(() { + locationController.text = + "${position.latitude}, ${position.longitude}"; + }); + } + }); + }, + ), + ), + ], + ), + // MIHTextField( + // controller: locationController, + // hintText: "Location", + // editable: false, + // required: false, + // ), + // const SizedBox(height: 10), + // SizedBox( + // width: 100.0, + // height: 50.0, + // child: MIHButton( + // buttonText: "Set", + // buttonColor: + // MzanziInnovationHub.of(context)!.theme.secondaryColor(), + // textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + // onTap: () { + // MIHLocationAPI().getGPSPosition(context).then((position) { + // if (position != null) { + // setState(() { + // locationController.text = + // "${position.latitude}, ${position.longitude}"; + // }); + // } + // }); + // }, + // ), + // ), + const SizedBox(height: 30), + SizedBox( + width: 500.0, + height: 50.0, + child: MIHButton( + buttonText: "Update", + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onTap: () { + submitForm(); + }, + ), + ), + ], + )); + } +} From 2fda834882fec1fa3998e620054cc7b793cc8b93 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 10:35:04 +0200 Subject: [PATCH 10/22] file manipulation apis updated --- backend/Minio_Storage/minioConnection.py | 18 +++++++++--------- backend/routers/fileStorage.py | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/backend/Minio_Storage/minioConnection.py b/backend/Minio_Storage/minioConnection.py index 0ec200a1..36aa03b9 100644 --- a/backend/Minio_Storage/minioConnection.py +++ b/backend/Minio_Storage/minioConnection.py @@ -1,7 +1,7 @@ from minio import Minio def minioConnect(env): - if(env == "Dev"): + # if(env == "Dev"): return Minio( "minio:9000", # "minio.mzansi-innovation-hub.co.za", @@ -9,11 +9,11 @@ def minioConnect(env): secret_key="nEED72ZlKYgDqH9Iy46fVGGT9TfabGWO", secure=False ) - else: - return Minio( - #"minio:9000", - "minio.mzansi-innovation-hub.co.za", - access_key="0RcgutfvcDq28lz7", - secret_key="nEED72ZlKYgDqH9Iy46fVGGT9TfabGWO", - secure=True - ) \ No newline at end of file + # else: + # return Minio( + # #"minio:9000", + # "minio.mzansi-innovation-hub.co.za", + # access_key="0RcgutfvcDq28lz7", + # secret_key="nEED72ZlKYgDqH9Iy46fVGGT9TfabGWO", + # secure=True + # ) \ No newline at end of file diff --git a/backend/routers/fileStorage.py b/backend/routers/fileStorage.py index e4e7e42e..7d95aedb 100644 --- a/backend/routers/fileStorage.py +++ b/backend/routers/fileStorage.py @@ -183,7 +183,7 @@ async def upload_perscription_to_user(requestItem: claimStatementUploud, session return {"message": "Successfully Generated File"} def uploudFile(app_id, folder, fileName, extension, content): - client = Minio_Storage.minioConnection.minioConnect("Dev") + client = Minio_Storage.minioConnection.minioConnect("Prod") found = client.bucket_exists("mih") if not found: client.make_bucket("mih") @@ -198,7 +198,7 @@ def uploudFile(app_id, folder, fileName, extension, content): content_type=f"application/{extension}") def uploudMedCert(requestItem: medCertUploud): - client = Minio_Storage.minioConnection.minioConnect("Prod") + client = Minio_Storage.minioConnection.minioConnect("Dev") generateMedCertPDF(requestItem) today = datetime.today().strftime('%Y-%m-%d') found = client.bucket_exists("mih") From 13112cfd1937d8e58ec35670b235e19145821a78 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 12:06:14 +0200 Subject: [PATCH 11/22] update example folder anem to example --- .../mih_package_components/{test => Example}/package_test.dart | 0 .../{test => Example}/package_tools/package_tool_one.dart | 0 .../{test => Example}/package_tools/package_tool_two.dart | 0 Frontend/lib/mih_router/routeGenerator.dart | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename Frontend/lib/mih_components/mih_package_components/{test => Example}/package_test.dart (100%) rename Frontend/lib/mih_components/mih_package_components/{test => Example}/package_tools/package_tool_one.dart (100%) rename Frontend/lib/mih_components/mih_package_components/{test => Example}/package_tools/package_tool_two.dart (100%) diff --git a/Frontend/lib/mih_components/mih_package_components/test/package_test.dart b/Frontend/lib/mih_components/mih_package_components/Example/package_test.dart similarity index 100% rename from Frontend/lib/mih_components/mih_package_components/test/package_test.dart rename to Frontend/lib/mih_components/mih_package_components/Example/package_test.dart diff --git a/Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_one.dart b/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart similarity index 100% rename from Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_one.dart rename to Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart diff --git a/Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_two.dart b/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_two.dart similarity index 100% rename from Frontend/lib/mih_components/mih_package_components/test/package_tools/package_tool_two.dart rename to Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_two.dart diff --git a/Frontend/lib/mih_router/routeGenerator.dart b/Frontend/lib/mih_router/routeGenerator.dart index 5a687d3e..05331d43 100644 --- a/Frontend/lib/mih_router/routeGenerator.dart +++ b/Frontend/lib/mih_router/routeGenerator.dart @@ -1,4 +1,4 @@ -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/test/package_test.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/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'; From 88380dca8c721e2b0a7e2d4087ba3ff49ca42367 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 12:06:24 +0200 Subject: [PATCH 12/22] same --- .../mih_package_components/Example/package_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/Example/package_test.dart b/Frontend/lib/mih_components/mih_package_components/Example/package_test.dart index a91025a1..474a33fb 100644 --- a/Frontend/lib/mih_components/mih_package_components/Example/package_test.dart +++ b/Frontend/lib/mih_components/mih_package_components/Example/package_test.dart @@ -3,8 +3,8 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_tools.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/test/package_tools/package_tool_one.dart'; -import 'package:mzansi_innovation_hub/mih_components/mih_package_components/test/package_tools/package_tool_two.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/Example/package_tools/package_tool_two.dart'; import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; import 'package:flutter/material.dart'; From 4681d53b0c214c835e1cf6550084d85ab06e9bea Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 12:46:55 +0200 Subject: [PATCH 13/22] new package component, mih image dsplay --- .../mih_image_display.dart | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 Frontend/lib/mih_components/mih_package_components/mih_image_display.dart diff --git a/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart b/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart new file mode 100644 index 00000000..c7e75f81 --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_image_display.dart @@ -0,0 +1,124 @@ +import 'dart:io'; + +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/main.dart'; + +class MihImageDisplay extends StatefulWidget { + final ImageProvider? imageFile; + final double width; + final bool editable; + final TextEditingController fileNameController; + final onChange; + final PlatformFile? userSelectedfile; + const MihImageDisplay({ + super.key, + required this.imageFile, + required this.width, + required this.editable, + required this.fileNameController, + required this.userSelectedfile, + required this.onChange, + }); + + @override + State createState() => _MihImageDisplayState(); +} + +class _MihImageDisplayState extends State { + late ImageProvider? imagePreview; + + @override + void initState() { + super.initState(); + setState(() { + imagePreview = widget.imageFile; + }); + } + + @override + Widget build(BuildContext context) { + return Container( + // color: Colors.white, + alignment: Alignment.center, + width: widget.width, + child: Stack( + alignment: Alignment.center, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(widget.width * 0.1), + child: Image(image: imagePreview!), + ), + Visibility( + visible: widget.editable, + child: Positioned( + bottom: 0, + right: 0, + child: IconButton.filled( + style: IconButton.styleFrom( + backgroundColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + ), + color: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onPressed: () async { + try { + FilePickerResult? result = + await FilePicker.platform.pickFiles( + type: FileType.image, + ); + // print("Here 1"); + if (MzanziInnovationHub.of(context)!.theme.getPlatform() == + "Web") { + // print("Here 2"); + if (result == null) return; + // print("Here 3"); + PlatformFile? selectedFile = result.files.first; + setState(() { + // print("Here 4"); + widget.onChange(selectedFile); + // print("Here 5"); + imagePreview = MemoryImage(selectedFile.bytes!); + }); + + setState(() { + widget.fileNameController.text = selectedFile.name; + }); + } else { + if (result != null) { + File file = File(result.files.single.path!); + PlatformFile? androidFile = PlatformFile( + path: file.path, + name: file.path.split('/').last, + size: file.lengthSync(), + bytes: await file.readAsBytes(), // Read file bytes + //extension: fileExtension, + ); + setState(() { + widget.onChange(androidFile); + imagePreview = FileImage(file); + }); + + setState(() { + widget.fileNameController.text = + file.path.split('/').last; + }); + } else { + print("here in else"); + // User canceled the picker + } + } + } catch (e) { + print("Error: $e"); + } + }, + icon: const Icon( + Icons.edit, + ), + ), + ), + ), + ], + ), + ); + } +} From e75d4484389baee0f32a2781680cfe6f83d6a94f Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 12:47:17 +0200 Subject: [PATCH 14/22] remove unnessasary code --- .../lib/mih_apis/mih_business_details_apis.dart | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Frontend/lib/mih_apis/mih_business_details_apis.dart b/Frontend/lib/mih_apis/mih_business_details_apis.dart index 38aa50a4..eec80814 100644 --- a/Frontend/lib/mih_apis/mih_business_details_apis.dart +++ b/Frontend/lib/mih_apis/mih_business_details_apis.dart @@ -2,21 +2,11 @@ import 'dart:convert'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; import 'package:flutter/material.dart'; -import 'package:geolocator/geolocator.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:supertokens_flutter/http.dart' as http; class MihBusinessDetailsApi { - final LocationSettings locationSettings = const LocationSettings( - accuracy: LocationAccuracy.high, - distanceFilter: 100, - ); - - ///This function is to get the current location of the signed in user. - ///First checks the permission, if permission is denied (new user), request permission from user. - ///if user has blocked permission (denied or denied forver), user will get error pop up. - ///if user has granted permission (while in use), function will return Position object. Future updateBusinessDetails( String business_id, String business_name, @@ -36,7 +26,6 @@ class MihBusinessDetailsApi { return const Mihloadingcircle(); }, ); - print("Here 1"); var response = await http.put( Uri.parse("${AppEnviroment.baseApiUrl}/business/update/"), headers: { @@ -56,13 +45,10 @@ class MihBusinessDetailsApi { "vat_no": business_vat_no, }), ); - print("Here 2"); Navigator.of(context).pop(); if (response.statusCode == 200) { - print("Here 3"); return 200; } else { - print("Here 4"); internetConnectionPopUp(context); return 500; } From 590e93dcd97e3a3c5f500cfb577d0c739bc94a3b Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 12:47:49 +0200 Subject: [PATCH 15/22] creat up design --- .../package_tools/mih_business_details.dart | 119 +++++++----------- 1 file changed, 48 insertions(+), 71 deletions(-) diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart index d620acc7..4c3d195d 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart @@ -10,8 +10,8 @@ import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih-app_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.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_components/mih_pop_up_messages/mih_success_message.dart'; import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; @@ -98,7 +98,7 @@ class _MihBusinessDetailsState extends State { alertBody: Column( children: [ Text( - "Hi there! To jump into the MIH Home Package, you'll need to set up biometric authentication (like fingerprint or face ID) on your device first. It looks like it's not quite ready yet.\n\nPlease head over to your device's settings to enable it, or press the button below to start the set up process now.", + "An error occurred while updating the business details. Please check internet connection and try again.", style: TextStyle( color: MzanziInnovationHub.of(context)! .theme @@ -245,49 +245,53 @@ class _MihBusinessDetailsState extends State { fontWeight: FontWeight.bold, ), ), - const SizedBox(height: 20), + Divider(color: MzanziInnovationHub.of(context)?.theme.secondaryColor()), + const SizedBox(height: 10), FutureBuilder( - future: fileUrlFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: Mihloadingcircle()); - } else if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData && - snapshot.data != null && - snapshot.data.toString().isNotEmpty) { - return MihCircleAvatar( - imageFile: NetworkImage(snapshot.data.toString()), - width: 150, - editable: true, - fileNameController: fileNameController, - userSelectedfile: imageFile, - frameColor: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - onChange: (selectedfile) { - setState(() { - imageFile = selectedfile; - }); - }, - ); - // MIHProfilePicture( - // profilePictureFile: NetworkImage(snapshot.data.toString()), - // proPicController: TextEditingController(), - // proPic: null, - // width: 100, - // radius: 50, - // drawerMode: false, - // editable: false, - // onChange: () {}, - // frameColor: Colors.white, - // ); - } else if (snapshot.hasError) { - return Text("Error: ${snapshot.error}"); - } else { - return const Text("Error loading image"); - } - }), + future: fileUrlFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Container( + // alignment: Alignment.center, + width: 150, + height: 150, + child: FittedBox( + alignment: Alignment.center, + fit: BoxFit.fill, + child: Icon( + MihIcons.mihCircleFrame, + color: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + ), + ), + ); + } else if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData && + snapshot.data != null && + snapshot.data.toString().isNotEmpty) { + return MihCircleAvatar( + imageFile: NetworkImage(snapshot.data.toString()), + width: 150, + editable: true, + fileNameController: fileNameController, + userSelectedfile: imageFile, + frameColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + onChange: (selectedfile) { + setState(() { + imageFile = selectedfile; + }); + }, + ); + } else if (snapshot.hasError) { + return Text("Error: ${snapshot.error}"); + } else { + return const Text("Error loading image"); + } + }, + ), Visibility( - visible: true, + visible: false, child: MIHTextField( controller: fileNameController, hintText: "Selected File Name", @@ -379,34 +383,7 @@ class _MihBusinessDetailsState extends State { ), ], ), - // MIHTextField( - // controller: locationController, - // hintText: "Location", - // editable: false, - // required: false, - // ), - // const SizedBox(height: 10), - // SizedBox( - // width: 100.0, - // height: 50.0, - // child: MIHButton( - // buttonText: "Set", - // buttonColor: - // MzanziInnovationHub.of(context)!.theme.secondaryColor(), - // textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), - // onTap: () { - // MIHLocationAPI().getGPSPosition(context).then((position) { - // if (position != null) { - // setState(() { - // locationController.text = - // "${position.latitude}, ${position.longitude}"; - // }); - // } - // }); - // }, - // ), - // ), - const SizedBox(height: 30), + const SizedBox(height: 15), SizedBox( width: 500.0, height: 50.0, From aff38c93a249f5c5d658cdd12d36d06ff618073a Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 12:48:30 +0200 Subject: [PATCH 16/22] update to slip business details and my business user --- .../mzansi_business_profile.dart | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart index 776be5d5..cfcdce15 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile.dart @@ -2,10 +2,11 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_action.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_tools.dart'; import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; -import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_profile.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_user_search.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_team.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart'; class MzansiBusinessProfile extends StatefulWidget { final BusinessArguments arguments; @@ -53,16 +54,26 @@ class _MzansiBusinessProfileState extends State { _selcetedIndex = 0; }); }; - temp[const Icon(Icons.people_outline)] = () { + temp[const Icon(Icons.person)] = () { setState(() { _selcetedIndex = 1; }); }; - temp[const Icon(Icons.add)] = () { + // temp[const Icon(Icons.warning)] = () { + // setState(() { + // _selcetedIndex = 2; + // }); + // }; + temp[const Icon(Icons.people)] = () { setState(() { _selcetedIndex = 2; }); }; + temp[const Icon(Icons.add)] = () { + setState(() { + _selcetedIndex = 3; + }); + }; return MihAppTools( tools: temp, selcetedIndex: _selcetedIndex, @@ -71,7 +82,9 @@ class _MzansiBusinessProfileState extends State { List getToolBody() { List toolBodies = [ - MihBusinessProfile(arguments: widget.arguments), + MihBusinessDetails(arguments: widget.arguments), + MihMyBusinessUser(arguments: widget.arguments), + // MihBusinessProfile(arguments: widget.arguments), MihMyBusinessTeam(arguments: widget.arguments), MihBusinessUserSearch(arguments: widget.arguments), ]; From 07ef522a1045bdcfc16bc1ceb77d522b9196f420 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 12:48:54 +0200 Subject: [PATCH 17/22] add mihimagedisplay to test --- .../package_tools/package_tool_one.dart | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart b/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart index 5d09fd24..ea56d9f5 100644 --- a/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart +++ b/Frontend/lib/mih_components/mih_package_components/Example/package_tools/package_tool_one.dart @@ -9,6 +9,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.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_image_display.dart'; class PackageToolOne extends StatefulWidget { const PackageToolOne({super.key}); @@ -20,7 +21,9 @@ class PackageToolOne extends StatefulWidget { class _PackageToolOneState extends State { late ImageProvider? imagePreview; PlatformFile? file; + PlatformFile? imageFile; TextEditingController _fileNameController = TextEditingController(); + TextEditingController _imagefileController = TextEditingController(); void showTestFullWindow() { showDialog( context: context, @@ -131,10 +134,30 @@ class _PackageToolOneState extends State { const SizedBox(height: 10), MIHTextField( controller: _fileNameController, - hintText: "Selected File", + hintText: "Selected Avatar File", editable: false, required: false, - ) + ), + const SizedBox(height: 10), + MihImageDisplay( + imageFile: imagePreview, + width: 300, + editable: true, + fileNameController: _imagefileController, + userSelectedfile: imageFile, + onChange: (selectedFile) { + setState(() { + imageFile = selectedFile; + }); + }, + ), + const SizedBox(height: 10), + MIHTextField( + controller: _imagefileController, + hintText: "Selected Image File", + editable: false, + required: false, + ), ], ), ), From efda077a2a437c0cd69b705291dfe6f144df07bf Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 13:27:00 +0200 Subject: [PATCH 18/22] add core4ct error message --- .../business_profile/package_tools/mih_business_details.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart index 4c3d195d..ed3a9568 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart @@ -117,7 +117,7 @@ class _MihBusinessDetailsState extends State { showDialog( context: context, builder: (context) { - return const MIHErrorMessage(errorType: "Error"); + return const MIHErrorMessage(errorType: "Internet Connection"); }, ); } From 10f414e3b64e98aedd4fc1fd9b8c308ec381335e Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 13:27:11 +0200 Subject: [PATCH 19/22] legacy code --- .../package_tools/mih_business_profile.dart | 150 +++++++++++------- 1 file changed, 93 insertions(+), 57 deletions(-) diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_profile.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_profile.dart index f5791d2b..bab86b4a 100644 --- a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_profile.dart +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_profile.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_file_api.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_location_api.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; @@ -11,14 +12,13 @@ import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih- 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_components/mih_pop_up_messages/mih_success_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_profile_picture.dart'; import 'package:mzansi_innovation_hub/mih_env/env.dart'; import 'package:mzansi_innovation_hub/mih_objects/arguments.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:supertokens_flutter/http.dart' as http; -import 'package:http/http.dart' as http2; -import 'package:supertokens_flutter/supertokens.dart'; class MihBusinessProfile extends StatefulWidget { final BusinessArguments arguments; @@ -52,14 +52,18 @@ class _MihBusinessProfileState extends State { late PlatformFile? selectedLogo = null; late PlatformFile? selectedSignature = null; + PlatformFile? logoFile; + ImageProvider? logoPreview = null; final ValueNotifier busType = ValueNotifier(""); late String business_id; late String oldLogoPath; late String oldSigPath; + String logoUri = ""; Future updateBusinessProfileAPICall(String business_id) async { + print("inside update business profile api call"); showDialog( context: context, builder: (context) { @@ -89,9 +93,8 @@ class _MihBusinessProfileState extends State { if (response.statusCode == 200) { //var businessResponse = jsonDecode(response.body); //print(selectedLogo != null); - if (selectedLogo != null) { - uploadSelectedFile(selectedLogo, logonameController); - deleteFileApiCall(oldLogoPath); + if (logoFile != null) { + uploadSelectedFile(logoFile); } updateBusinessUserAPICall(business_id); } else { @@ -117,7 +120,7 @@ class _MihBusinessProfileState extends State { ); if (response.statusCode == 200) { if (selectedSignature != null) { - uploadSelectedFile(selectedSignature, signtureController); + uploadSelectedFile(selectedSignature); deleteFileApiCall(oldSigPath); } Navigator.of(context).pop(); @@ -138,23 +141,16 @@ class _MihBusinessProfileState extends State { } } - Future uploadSelectedFile( - PlatformFile? file, TextEditingController controller) async { - //to-do delete file when changed - var token = await SuperTokens.getAccessToken(); - //print(t); - //print("here1"); - var request = http2.MultipartRequest( - 'POST', Uri.parse("${AppEnviroment.baseApiUrl}/minio/upload/file/")); - request.headers['accept'] = 'application/json'; - request.headers['Authorization'] = 'Bearer $token'; - request.headers['Content-Type'] = 'multipart/form-data'; - request.fields['app_id'] = widget.arguments.signedInUser.app_id; - request.fields['folder'] = "business_files"; - request.files.add(await http2.MultipartFile.fromBytes('file', file!.bytes!, - filename: file.name.replaceAll(RegExp(r' '), '-'))); - var response1 = await request.send(); - if (response1.statusCode == 200) { + Future uploadSelectedFile(PlatformFile? file) async { + print("Inside upload selected file"); + var response = await MihFileApi.uploadFile( + widget.arguments.signedInUser.app_id, + "business_files", + file, + context, + ); + if (response == 200) { + deleteFileApiCall(oldLogoPath); } else { internetConnectionPopUp(); } @@ -162,16 +158,13 @@ class _MihBusinessProfileState extends State { Future deleteFileApiCall(String filePath) async { // delete file from minio - var response = await http.delete( - Uri.parse("$baseAPI/minio/delete/file/"), - headers: { - "Content-Type": "application/json; charset=UTF-8" - }, - body: jsonEncode({"file_path": filePath}), + var response = await MihFileApi.deleteFile( + widget.arguments.signedInUser.app_id, + "business_files", + filePath.split("/").last, + context, ); - //print("Here4"); - //print(response.statusCode); - if (response.statusCode == 200) { + if (response == 200) { //SQL delete } else { internetConnectionPopUp(); @@ -222,6 +215,7 @@ class _MihBusinessProfileState extends State { if (!validEmail()) { emailError(); } else if (isFieldsFilled()) { + print("inside submit form mthod"); updateBusinessProfileAPICall(business_id); } else { showDialog( @@ -263,6 +257,20 @@ class _MihBusinessProfileState extends State { ); } + ImageProvider? isPictureAvailable(String url) { + print("logo Url: $url"); + if (url == "") { + return const AssetImage( + 'lib/mih_components/mih_package_components/assets/images/i-dont-know-2.png'); + } else if (url != "") { + return NetworkImage(url); + } else { + return const AssetImage( + 'lib/mih_components/mih_package_components/assets/images/i-dont-know-2.png'); + // return null; + } + } + @override void dispose() { nameController.dispose(); @@ -306,6 +314,15 @@ class _MihBusinessProfileState extends State { practiceNoController.text = widget.arguments.business!.practice_no; vatNoController.text = widget.arguments.business!.vat_no; }); + MihFileApi.getMinioFileUrl( + widget.arguments.business!.logo_path, + context, + ).then((value) { + setState(() { + logoUri = value; + }); + logoPreview = isPictureAvailable(logoUri); + }); super.initState(); } @@ -343,8 +360,48 @@ class _MihBusinessProfileState extends State { ), ), Divider( - color: - MzanziInnovationHub.of(context)?.theme.secondaryColor(), + color: MzanziInnovationHub.of(context) + ?.theme + .secondaryColor()), + const SizedBox(height: 10.0), + MIHProfilePicture( + profilePictureFile: logoPreview, + proPicController: logonameController, + proPic: logoFile, + width: 155, + radius: 70, + drawerMode: false, + editable: true, + frameColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + onChange: (newProPic) { + setState(() { + logoFile = newProPic; + }); + print("logoFile: ${logoFile?.bytes}"); + }, + ), + const SizedBox(height: 10.0), + MIHFileField( + controller: logonameController, + hintText: "Logo", + editable: false, + required: true, + onPressed: () async { + FilePickerResult? result = + await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['jpg', 'png'], + ); + if (result == null) return; + final selectedFile = result.files.first; + setState(() { + selectedLogo = selectedFile; + }); + setState(() { + logonameController.text = selectedFile.name; + }); + }, ), const SizedBox(height: 10.0), MIHTextField( @@ -407,28 +464,6 @@ class _MihBusinessProfileState extends State { required: true, ), const SizedBox(height: 10.0), - MIHFileField( - controller: logonameController, - hintText: "Logo", - editable: false, - required: true, - onPressed: () async { - FilePickerResult? result = - await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: ['jpg', 'png', 'pdf'], - ); - if (result == null) return; - final selectedFile = result.files.first; - setState(() { - selectedLogo = selectedFile; - }); - setState(() { - logonameController.text = selectedFile.name; - }); - }, - ), - const SizedBox(height: 10.0), Row( children: [ Flexible( @@ -489,7 +524,7 @@ class _MihBusinessProfileState extends State { MIHDropdownField( controller: titleController, hintText: "Title", - dropdownOptions: const ["Doctor", "Assistant"], + dropdownOptions: const ["Doctor", "Assistant", "Other"], required: true, editable: true, enableSearch: false, @@ -551,6 +586,7 @@ class _MihBusinessProfileState extends State { MzanziInnovationHub.of(context)!.theme.primaryColor(), onTap: () { //print(business_id); + print("submit form call"); submitForm(business_id); }, ), From fa1076927c6cd771bd5d6f6317f9b252efd8b4bc Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 13:27:27 +0200 Subject: [PATCH 20/22] new my business user tool --- .../mih_apis/mih_my_business_user_apis.dart | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Frontend/lib/mih_apis/mih_my_business_user_apis.dart diff --git a/Frontend/lib/mih_apis/mih_my_business_user_apis.dart b/Frontend/lib/mih_apis/mih_my_business_user_apis.dart new file mode 100644 index 00000000..ca85baae --- /dev/null +++ b/Frontend/lib/mih_apis/mih_my_business_user_apis.dart @@ -0,0 +1,75 @@ +import 'dart:convert'; + +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_env/env.dart'; +import '../mih_components/mih_pop_up_messages/mih_error_message.dart'; +import 'package:supertokens_flutter/http.dart' as http; + +class MihMyBusinessUserApi { + /// This function updates the business user details. + Future updateBusinessDetails( + String app_id, + String business_id, + String bUserTitle, + String bUserAccess, + String signatureFileName, + BuildContext context, + ) async { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle(); + }, + ); + var response = await http.put( + Uri.parse("${AppEnviroment.baseApiUrl}/business-user/update/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "business_id": business_id, + "app_id": app_id, + "signature": signatureFileName, + "sig_path": "$app_id/business_files/$signatureFileName", + "title": bUserTitle, + "access": bUserAccess, + }), + ); + // var response = await http.put( + // Uri.parse("${AppEnviroment.baseApiUrl}/business/update/"), + // headers: { + // "Content-Type": "application/json; charset=UTF-8" + // }, + // body: jsonEncode({ + // "business_id": business_id, + // "Name": business_name, + // "type": business_type, + // "registration_no": business_registration_no, + // "logo_name": business_logo_name, + // "logo_path": "$business_id/business_files/$business_logo_name", + // "contact_no": business_phone_number, + // "bus_email": business_email, + // "gps_location": business_location, + // "practice_no": business_practice_no, + // "vat_no": business_vat_no, + // }), + // ); + Navigator.of(context).pop(); + if (response.statusCode == 200) { + return 200; + } else { + internetConnectionPopUp(context); + return 500; + } + } + + void internetConnectionPopUp(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Internet Connection"); + }, + ); + } +} From accb5ecfb9f142f5d9b405c236334a316b515dd0 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 13:27:39 +0200 Subject: [PATCH 21/22] and api --- .../package_tools/mih_my_business_user.dart | 399 ++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart new file mode 100644 index 00000000..eef5bbef --- /dev/null +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart @@ -0,0 +1,399 @@ +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_apis/mih_file_api.dart'; +import 'package:mzansi_innovation_hub/mih_apis/mih_my_business_user_apis.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih-app_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_circle_avatar.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_image_display.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_objects/arguments.dart'; + +class MihMyBusinessUser extends StatefulWidget { + final BusinessArguments arguments; + const MihMyBusinessUser({ + super.key, + required this.arguments, + }); + + @override + State createState() => _MihMyBusinessUserState(); +} + +class _MihMyBusinessUserState extends State { + late Future userPicUrlFuture; + late Future userSignatureUrlFuture; + PlatformFile? userPicFile; + PlatformFile? userSignatureFile; + final fileNameController = TextEditingController(); + final titleDropdownController = TextEditingController(); + final titleTextController = TextEditingController(); + final fnameController = TextEditingController(); + final lnameController = TextEditingController(); + final accessController = TextEditingController(); + final signtureController = TextEditingController(); + + bool isFormFilled() { + if (signtureController.text.isEmpty || + titleDropdownController.text.isEmpty || + titleTextController.text.isEmpty || + fnameController.text.isEmpty || + lnameController.text.isEmpty || + accessController.text.isEmpty) { + return false; + } else { + return true; + } + } + + Future uploadFile() async { + if (userSignatureFile != null) { + print(userSignatureFile!.name); + print(userSignatureFile!.bytes); + int uploadStatusCode = 0; + uploadStatusCode = await MihFileApi.uploadFile( + widget.arguments.signedInUser.app_id, + "business_files", + userSignatureFile!, + context, + ); + if (uploadStatusCode == 200) { + int deleteStatusCode = 0; + deleteStatusCode = await MihFileApi.deleteFile( + widget.arguments.signedInUser.app_id, + "business_files", + widget.arguments.businessUser!.sig_path.split("/").last, + context, + ); + if (deleteStatusCode == 200) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return true; // No file selected, so no upload needed + } + } + + Future submitForm() async { + print("Here 1"); + if (isFormFilled()) { + print("Here 1"); + int statusCode = await MihMyBusinessUserApi().updateBusinessDetails( + widget.arguments.signedInUser.app_id, + widget.arguments.businessUser!.business_id, + titleDropdownController.text, + accessController.text, + signtureController.text, + context, + ); + if (statusCode == 200) { + print("Here 1"); + bool successfullyUploadedFile = await uploadFile(); + print("Here 4"); + if (successfullyUploadedFile) { + Navigator.of(context).pop(); + Navigator.of(context).pop(); + Navigator.of(context).pushNamed( + '/', + arguments: AuthArguments( + false, + false, + ), + ); + // File uploaded successfully + showDialog( + context: context, + builder: (context) { + return const MIHSuccessMessage( + successType: "Success", + successMessage: "Business details updated successfully", + ); + }, + ); + } else { + // File upload failed + showDialog( + context: context, + builder: (context) { + return MihAppAlert( + alertIcon: Icon( + Icons.warning_rounded, + color: MzanziInnovationHub.of(context)!.theme.errorColor(), + ), + alertTitle: "Error Updating Business User Details", + alertBody: Column( + children: [ + Text( + "An error occurred while updating the business User details. Please check internet connection and try again.", + style: TextStyle( + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + ), + ), + ], + ), + alertColour: + MzanziInnovationHub.of(context)!.theme.errorColor(), + ); + }, + ); + } + } else { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Internet Connection"); + }, + ); + } + } else { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Input Error"); + }, + ); + } + } + + @override + void dispose() { + super.dispose(); + fileNameController.dispose(); + titleDropdownController.dispose(); + titleTextController.dispose(); + fnameController.dispose(); + lnameController.dispose(); + accessController.dispose(); + signtureController.dispose(); + userPicFile = null; + userSignatureFile = null; + } + + @override + void initState() { + super.initState(); + setState(() { + fileNameController.text = + widget.arguments.signedInUser.pro_pic_path.split("/").last; + signtureController.text = + widget.arguments.businessUser!.sig_path.split("/").last; + titleDropdownController.text = widget.arguments.businessUser!.title; + titleTextController.text = widget.arguments.businessUser!.title; + fnameController.text = widget.arguments.signedInUser.fname; + lnameController.text = widget.arguments.signedInUser.lname; + accessController.text = widget.arguments.businessUser!.access; + }); + userPicUrlFuture = MihFileApi.getMinioFileUrl( + widget.arguments.signedInUser.pro_pic_path, + context, + ); + userSignatureUrlFuture = MihFileApi.getMinioFileUrl( + widget.arguments.businessUser!.sig_path, + context, + ); + } + + @override + Widget build(BuildContext context) { + return MihAppToolBody( + borderOn: true, + bodyItem: getBody(), + ); + } + + Widget getBody() { + return MihSingleChildScroll( + child: Column( + children: [ + const Text( + "My Business User", + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + Divider( + color: MzanziInnovationHub.of(context)?.theme.secondaryColor()), + const SizedBox(height: 10), + FutureBuilder( + future: userPicUrlFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Container( + // alignment: Alignment.center, + width: 150, + height: 150, + child: FittedBox( + alignment: Alignment.center, + fit: BoxFit.fill, + child: Icon( + MihIcons.mihCircleFrame, + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + ), + ), + ); + } else if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData && + snapshot.data != null && + snapshot.data.toString().isNotEmpty) { + return MihCircleAvatar( + imageFile: NetworkImage(snapshot.data.toString()), + width: 150, + editable: false, + fileNameController: fileNameController, + userSelectedfile: userPicFile, + frameColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + onChange: (_) {}, + ); + } else if (snapshot.hasError) { + return Text("Error: ${snapshot.error}"); + } else { + return const Text("Error loading image"); + } + }, + ), + Visibility( + visible: false, + child: MIHTextField( + controller: fileNameController, + hintText: "Selected File Name", + editable: false, + required: false, + ), + ), + const SizedBox(height: 20), + MIHDropdownField( + controller: titleDropdownController, + hintText: "Title", + dropdownOptions: const ["Doctor", "Assistant", "Other"], + required: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 10), + MIHTextField( + controller: titleTextController, + hintText: "Other Title", + editable: true, + required: true, + ), + const SizedBox(height: 10), + MIHTextField( + controller: fnameController, + hintText: "Name", + editable: false, + required: true, + ), + const SizedBox(height: 10), + MIHTextField( + controller: lnameController, + hintText: "Surname", + editable: false, + required: true, + ), + const SizedBox(height: 10), + MIHTextField( + controller: accessController, + hintText: "Access Level", + editable: false, + required: true, + ), + const SizedBox(height: 10), + Container( + width: 300, + alignment: Alignment.topLeft, + child: const Text( + "Signature", + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + FutureBuilder( + future: userSignatureUrlFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Container( + // alignment: Alignment.center, + width: 300, + height: 200, + child: FittedBox( + alignment: Alignment.center, + fit: BoxFit.fill, + child: Icon( + MihIcons.mihCircleFrame, + color: MzanziInnovationHub.of(context)! + .theme + .secondaryColor(), + ), + ), + ); + } else if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData && + snapshot.data != null && + snapshot.data.toString().isNotEmpty) { + return MihImageDisplay( + imageFile: NetworkImage(snapshot.data.toString()), + width: 300, + editable: true, + fileNameController: signtureController, + userSelectedfile: userSignatureFile, + onChange: (selectedFile) { + setState(() { + userSignatureFile = selectedFile; + }); + }, + ); + } else if (snapshot.hasError) { + return Text("Error: ${snapshot.error}"); + } else { + return const Text("Error loading image"); + } + }, + ), + const SizedBox(height: 10), + Visibility( + visible: false, + child: MIHTextField( + controller: signtureController, + hintText: "Selected Signature File", + editable: false, + required: true, + ), + ), + const SizedBox(height: 15), + SizedBox( + width: 500.0, + height: 50.0, + child: MIHButton( + buttonText: "Update", + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + onTap: () { + submitForm(); + }, + ), + ), + ], + ), + ); + } +} From da1dd8c60dc08c48f308984ec686725d28887684 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 24 Apr 2025 13:31:49 +0200 Subject: [PATCH 22/22] update api python to use prod --- backend/routers/fileStorage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/routers/fileStorage.py b/backend/routers/fileStorage.py index 7d95aedb..8ae1c48a 100644 --- a/backend/routers/fileStorage.py +++ b/backend/routers/fileStorage.py @@ -198,7 +198,7 @@ def uploudFile(app_id, folder, fileName, extension, content): content_type=f"application/{extension}") def uploudMedCert(requestItem: medCertUploud): - client = Minio_Storage.minioConnection.minioConnect("Dev") + client = Minio_Storage.minioConnection.minioConnect("Prod") generateMedCertPDF(requestItem) today = datetime.today().strftime('%Y-%m-%d') found = client.bucket_exists("mih")