diff --git a/docker-compose.yml b/docker-compose.yml index 3b1750ed..68527e5e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -155,10 +155,23 @@ services: MYSQL_DATABASE: ${SUPERTOKENS_DB} networks: - mih-network - ports: - - "127.0.0.1:3306:3306" + # ports: + # - "127.0.0.1:3306:3306" volumes: - ./mih_db:/var/lib/mysql + #============== Adminer ==================================================================== + mih-adminer: + image: adminer:latest + container_name: mih-adminer + restart: always + environment: + ADMINER_DEFAULT_SERVER: mih-db + ports: + - "127.0.0.1:8082:8080" + networks: + - mih-network + depends_on: + - mih-db #============== PHP My Admin ==================================================================== # phpmyadmin: # platform: linux/amd64 diff --git a/mih_api_hub/routers/profile_links.py b/mih_api_hub/routers/profile_links.py new file mode 100644 index 00000000..4c7bb877 --- /dev/null +++ b/mih_api_hub/routers/profile_links.py @@ -0,0 +1,128 @@ +from fastapi import APIRouter, HTTPException, status +from pydantic import BaseModel +from typing import List +#from ..mih_database import dbConnection +import mih_database +import mih_database.mihDbConnections +from mih_database.mihDbObjects import ProfileLink +from sqlalchemy import select, insert, delete, CursorResult +from sqlalchemy.orm import Session +#SuperToken Auth from front end +from supertokens_python.recipe.session.framework.fastapi import verify_session +from supertokens_python.recipe.session import SessionContainer + +from fastapi import Depends + +router = APIRouter() + +class ProfileLinkResponse(BaseModel): + idprofile_links: int + app_id: str + business_id: str + site_name: str + custom_name: str + destination: str + order: int + + class Config: + from_attributes = True + +class profileLinkInsertRequest(BaseModel): + app_id: str + business_id: str + site_name: str + custom_name: str + destination: str + order:int + +class profileLinkDeletRequest(BaseModel): + idprofile_links: int + +class profileLinkUpdateRequest(BaseModel): + idprofile_links: int + site_name: str + custom_name: str + destination: str + order:int + +def get_db(): + dbEngine = mih_database.mihDbConnections.dbAllConnect() + with Session(dbEngine) as session: + yield session + +@router.get("/profile-links/user/{app_id}", response_model=List[ProfileLinkResponse], tags=["Profile Links"]) +async def getUserProfileLinks( + app_id: str, + dbSession: Session = Depends(get_db), + # session: SessionContainer = Depends(verify_session()) + ): + + queryStatement = select(ProfileLink).where(ProfileLink.app_id == app_id).order_by(ProfileLink.order) + queryResults = dbSession.execute(queryStatement).scalars().all() + return queryResults + +@router.get("/profile-links/business/{business_id}", response_model=List[ProfileLinkResponse], tags=["Profile Links"]) +async def getBusinessProfileLinks( + business_id: str, + dbSession: Session = Depends(get_db), + # session: SessionContainer = Depends(verify_session()) + ): + queryStatement = select(ProfileLink).where(ProfileLink.business_id == business_id).order_by(ProfileLink.order) + queryResults = dbSession.execute(queryStatement).scalars().all() + return queryResults + +@router.post("/profile-links/insert/", status_code=201, tags = ["Profile Links"]) +async def addNewProfileLink( + insertItem: profileLinkInsertRequest, + dbSession: Session = Depends(get_db), + session: SessionContainer = Depends(verify_session()) + ): + queryStatement = insert(ProfileLink).values( + app_id = insertItem.app_id, + business_id = insertItem.business_id, + site_name = insertItem.site_name, + custom_name = insertItem.custom_name, + destination = insertItem.destination, + order = insertItem.order + ) + dbSession.execute(queryStatement) + dbSession.commit() + return {"message": "Successfully Created Record"} + +@router.delete("/profile-links/delete/", tags=["Profile Links"]) +async def deleteProfileLink( + deleteItem: profileLinkDeletRequest, + dbSession: Session = Depends(get_db), + session: SessionContainer = Depends(verify_session()) + ): + queryStatement = select(ProfileLink).where(ProfileLink.idprofile_links == deleteItem.idprofile_links) + profileLink = dbSession.execute(queryStatement).scalar_one_or_none() + + if not profileLink: + raise HTTPException(status_code=404, detail="Record not found") + + dbSession.delete(profileLink) + dbSession.execute(queryStatement) + dbSession.commit() + return {"message": "Successfully Deleted Record"} + +@router.put("/profile-links/update/", tags=["Profile Links"]) +async def updateProfileLink( + updateItem: profileLinkUpdateRequest, + dbSession: Session = Depends(get_db), + session: SessionContainer = Depends(verify_session()) + ): + queryStatement = select(ProfileLink).where(ProfileLink.idprofile_links == updateItem.idprofile_links) + profileLink = dbSession.execute(queryStatement).scalar_one_or_none() + + if not profileLink: + raise HTTPException(status_code=404, detail="Link not found") + + profileLink.site_name = updateItem.site_name + profileLink.custom_name = updateItem.custom_name + profileLink.destination = updateItem.destination + profileLink.order = updateItem.order + + dbSession.commit() + return {"message": "Successfully Updated Record"} + diff --git a/mih_api_hub/routers/users.py b/mih_api_hub/routers/users.py index a065e41b..0ed38e77 100644 --- a/mih_api_hub/routers/users.py +++ b/mih_api_hub/routers/users.py @@ -136,6 +136,34 @@ async def read_all_users(username: str, session: SessionContainer = Depends(veri db.close() return {"available": available} +# Get List of all files +@router.get("/user/username/{username}", tags=["MIH Users"]) +async def read_users_by_username(username: str, + # session: SessionContainer = Depends(verify_session()), + ): + db = mih_database.dbConnection.dbAppDataConnect() + cursor = db.cursor() + # query = "SELECT * FROM users where username = %s" + query = "SELECT * FROM users WHERE LOWER(username) = LOWER(%s)" + cursor.execute(query, (username,)) + items = [ + { + "idUser": item[0], + "email": item[1], + "fname": item[2], + "lname": item[3], + "type": item[4], + "app_id": item[5], + "username": item[6], + "pro_pic_path": item[7], + "purpose": item[8], + } + for item in cursor.fetchall() + ] + cursor.close() + db.close() + return items[0] + # Get List of all files @router.get("/user/{app_id}", tags=["MIH Users"]) async def read_users_by_app_id(app_id: str, session: SessionContainer = Depends(verify_session())): diff --git a/mih_ui/lib/mih_config/mih_go_router.dart b/mih_ui/lib/mih_config/mih_go_router.dart index d7b0726a..5433bcce 100644 --- a/mih_ui/lib/mih_config/mih_go_router.dart +++ b/mih_ui/lib/mih_config/mih_go_router.dart @@ -77,7 +77,8 @@ class MihGoRouter { "${MihGoRouterPaths.mihAuthentication}/${MihGoRouterPaths.forgotPassword}", MihGoRouterPaths.resetPassword, "/${MihGoRouterPaths.aboutMih}", - MihGoRouterPaths.businessProfileView, + "/${MihGoRouterPaths.businessProfileView}", + "/${MihGoRouterPaths.mzansiProfileView}", ]; KenLogger.success( "Redirect Check: ${state.fullPath}, isUserSignedIn: $isUserSignedIn"); @@ -86,8 +87,9 @@ class MihGoRouter { } if (isUserSignedIn && unauthenticatedPaths.contains(state.fullPath) && - state.fullPath != MihGoRouterPaths.aboutMih && - state.fullPath != MihGoRouterPaths.businessProfileView) { + state.fullPath != "/${MihGoRouterPaths.aboutMih}" && + state.fullPath != "/${MihGoRouterPaths.mzansiProfileView}" && + state.fullPath != "/${MihGoRouterPaths.businessProfileView}") { return MihGoRouterPaths.mihHome; } return null; // Stay on current route @@ -161,16 +163,21 @@ class MihGoRouter { name: "mzansiProfileView", path: MihGoRouterPaths.mzansiProfileView, builder: (BuildContext context, GoRouterState state) { + KenLogger.success("MihGoRouter: mzansiProfileView"); + String? username = state.uri.queryParameters['username']; + KenLogger.success("username: username"); KenLogger.success("MihGoRouter: mzansiProfileView"); MzansiDirectoryProvider directoryProvider = context.read(); - if (directoryProvider.selectedUser == null) { + if (directoryProvider.selectedUser == null && username == null) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go(MihGoRouterPaths.mihHome); }); return const SizedBox.shrink(); } - return MzansiProfileView(); + return MzansiProfileView( + username: username, + ); }, ), // ========================== Mzansi Profile Business ================================== @@ -186,9 +193,9 @@ class MihGoRouter { name: "businessProfileView", path: MihGoRouterPaths.businessProfileView, builder: (BuildContext context, GoRouterState state) { - KenLogger.success("MihGoRouter: businessProfileView"); + // KenLogger.success("MihGoRouter: businessProfileView"); String? businessId = state.uri.queryParameters['business_id']; - KenLogger.success("businessId: $businessId"); + // KenLogger.success("businessId: $businessId"); MzansiDirectoryProvider directoryProvider = context.read(); if (directoryProvider.selectedBusiness == null && diff --git a/mih_ui/lib/mih_objects/profile_link.dart b/mih_ui/lib/mih_objects/profile_link.dart index 103a1e72..20ef0a08 100644 --- a/mih_ui/lib/mih_objects/profile_link.dart +++ b/mih_ui/lib/mih_objects/profile_link.dart @@ -2,15 +2,19 @@ class ProfileLink { final int idprofile_links; final String app_id; final String business_id; + final String site_name; + final String custom_name; final String destination; - final String web_link; + final int order; const ProfileLink({ required this.idprofile_links, required this.app_id, required this.business_id, + required this.site_name, + required this.custom_name, required this.destination, - required this.web_link, + required this.order, }); factory ProfileLink.fromJson(Map json) { @@ -18,8 +22,10 @@ class ProfileLink { idprofile_links: json['idprofile_links'], app_id: json['app_id'], business_id: json['business_id'], + site_name: json['site_name'], + custom_name: json['custom_name'], destination: json['destination'], - web_link: json['web_link'], + order: json['order'], ); } @@ -28,8 +34,10 @@ class ProfileLink { 'idprofile_links': idprofile_links, 'app_id': app_id, 'business_id': business_id, + 'site_name': site_name, + 'custom_name': custom_name, 'destination': destination, - 'web_link': web_link, + 'order': order, }; } } diff --git a/mih_ui/lib/mih_package_components/Example/package_tiles/test_package_tile.dart b/mih_ui/lib/mih_package_components/Example/package_tiles/test_package_tile.dart index e69c7c84..f00e12a3 100644 --- a/mih_ui/lib/mih_package_components/Example/package_tiles/test_package_tile.dart +++ b/mih_ui/lib/mih_package_components/Example/package_tiles/test_package_tile.dart @@ -18,7 +18,7 @@ class _TestPackageTileState extends State { Widget build(BuildContext context) { return MihPackageTile( onTap: () { - context.pushNamed( + context.goNamed( 'testPackage', ); // Navigator.of(context).pushNamed( diff --git a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_three.dart b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_three.dart index b46dd897..49700a07 100644 --- a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_three.dart +++ b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_three.dart @@ -11,6 +11,227 @@ class PackageToolThree extends StatefulWidget { } class _PackageToolThreeState extends State { + List links = [ + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "YouTube", + custom_name: "", + destination: "https://www.youtube.com/@MzansiInnovationHub", + order: 1, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Threads", + custom_name: "", + destination: "https://www.threads.com/@mzansi.innovation.hub", + order: 2, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "TikTok", + custom_name: "", + destination: "https://www.tiktok.com/@mzansiinnovationhub", + order: 3, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "WhatsApp", + custom_name: "", + destination: "https://whatsapp.com/channel/0029Vax3INCIyPtMn8KgeM2F", + order: 4, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Twitch", + custom_name: "", + destination: "https://www.twitch.tv/mzansiinnovationhub", + order: 5, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Instagram", + custom_name: "", + destination: "https://www.instagram.com/mzansi.innovation.hub/", + order: 6, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "X", + custom_name: "", + destination: "https://x.com/mzansi_inno_hub", + order: 7, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "LinkedIn", + custom_name: "", + destination: "https://www.linkedin.com/in/yasien-meth-172352108/", + order: 8, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Facebook", + custom_name: "", + destination: "https://www.facebook.com/profile.php?id=61565345762136", + order: 9, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Reddit", + custom_name: "", + destination: "https://www.reddit.com/r/Mzani_Innovation_Hub/", + order: 10, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Git", + custom_name: "", + destination: + "https://git.mzansi-innovation-hub.co.za/yaso_meth/mzansi_vim", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Telegram", + custom_name: "", + destination: "https://t.me/unisagroupschannel", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Pinterest", + custom_name: "", + destination: "https://za.pinterest.com/food/tomato-based-recipes-ideas/", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Snapchat", + custom_name: "", + destination: "https://www.snapchat.com/", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Messenger", + custom_name: "", + destination: "https://www.messenger.com/", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Medium", + custom_name: "", + destination: + "https://medium.com/flutter-community/the-ultimate-guide-flutter-architecture-template-ii-f86f9aa222e6", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Substack", + custom_name: "", + destination: "https://substack.com/@flutterbytes", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Spotify", + custom_name: "", + destination: "https://open.spotify.com/album/2oss3QgSxdNikts0shvMMo", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "YouTube Music", + custom_name: "", + destination: + "https://music.youtube.com/playlist?list=OLAK5uy_m9x66mE1zyhom3o_NPxmjf60HU1BjTXEE", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Apple Music", + custom_name: "", + destination: "https://music.apple.com/us/album/bastholile/1812031316", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Patreon", + custom_name: "", + destination: "https://www.patreon.com/c/MzansiInnovationHub", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Loolio", + custom_name: "", + destination: "https://www.loolio.com/user/mzansiinnovationhub", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "WeChat", + custom_name: "", + destination: "https://www.wechat.com/en", + order: 11, + ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + site_name: "Other", + custom_name: "My App", + destination: "https://app.mzansi-innovation-hub.co.za/about", + order: 12, + ), + ]; @override Widget build(BuildContext context) { return MihPackageToolBody( @@ -21,108 +242,47 @@ class _PackageToolThreeState extends State { } Widget getBody() { - List links = [ - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Youtube", - web_link: "https://www.youtube.com/@MzansiInnovationHub", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Threads", - web_link: "https://www.threads.com/@mzansi.innovation.hub", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "TikTok", - web_link: "https://www.tiktok.com/@mzansiinnovationhub", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "WhatsApp", - web_link: "https://whatsapp.com/channel/0029Vax3INCIyPtMn8KgeM2F", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Twitch", - web_link: "https://www.twitch.tv/mzansiinnovationhub", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Instagram", - web_link: "https://www.instagram.com/mzansi.innovation.hub/", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "X", - web_link: "https://x.com/mzansi_inno_hub", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "LinkedIn", - web_link: "https://www.linkedin.com/in/yasien-meth-172352108/", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Facebook", - web_link: "https://www.facebook.com/profile.php?id=61565345762136", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Reddit", - web_link: "https://www.reddit.com/r/Mzani_Innovation_Hub/", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Discord", - web_link: "https://discord.gg/ZtTZYd5d", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "My App", - web_link: "https://app.mzansi-innovation-hub.co.za/about", - ), - ]; - - return Stack( + return + // Column( + // mainAxisAlignment: MainAxisAlignment.center, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // MihProfileLinks( + // links: links, + // // links: [], + // ), + // const SizedBox( + // height: 20, + // ), + Column( children: [ - MihSingleChildScroll( - scrollbarOn: true, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - MihProfileLinks( - links: links, - // links: [], - ), - ], + MihProfileLinks( + links: links, + // links: [], + ), + Expanded( + child: ReorderableListView.builder( + itemBuilder: (context, index) { + return ListTile( + key: ValueKey("$index"), + title: Text("Link SIte: ${links[index].site_name}"), + ); + }, + itemCount: links.length, + onReorder: (oldIndex, newIndex) { + setState(() { + if (oldIndex < newIndex) { + newIndex -= 1; + } + var link = links.removeAt(oldIndex); + links.insert(newIndex, link); + }); + }, ), ), ], ); + // ], + // ); } } diff --git a/mih_ui/lib/mih_package_components/mih_profile_links.dart b/mih_ui/lib/mih_package_components/mih_profile_links.dart index 8a42632d..12c091b7 100644 --- a/mih_ui/lib/mih_package_components/mih_profile_links.dart +++ b/mih_ui/lib/mih_package_components/mih_profile_links.dart @@ -24,72 +24,142 @@ class _MihProfileLinksState extends State { IconData iconData; Color btnColor; Color iconColor = Colors.white; - switch (link.destination.toLowerCase()) { + switch (link.site_name.toLowerCase()) { case "youtube": - iconData = FontAwesomeIcons.youtube; + // iconData = FontAwesomeIcons.youtube; + iconData = MihIcons.youtube; btnColor = const Color(0xFFFF0000); break; case "tiktok": - iconData = FontAwesomeIcons.tiktok; + iconData = MihIcons.tiktok; btnColor = const Color(0xFF000000); break; case "twitch": - iconData = FontAwesomeIcons.twitch; + iconData = MihIcons.twitch; btnColor = const Color(0xFF6441a5); break; case "threads": - iconData = FontAwesomeIcons.threads; + iconData = MihIcons.threads; btnColor = const Color(0xFF000000); break; case "whatsapp": - iconData = FontAwesomeIcons.whatsapp; + iconData = MihIcons.whatsapp; btnColor = const Color(0xFF25D366); break; case "instagram": - iconData = FontAwesomeIcons.instagram; + iconData = MihIcons.instagram; btnColor = const Color(0xFFF56040); break; case "x": - iconData = FontAwesomeIcons.xTwitter; + iconData = MihIcons.x; btnColor = const Color(0xFF000000); break; case "linkedin": - iconData = FontAwesomeIcons.linkedin; + iconData = MihIcons.linkedin; btnColor = const Color(0xFF0a66c2); break; case "facebook": - iconData = FontAwesomeIcons.facebook; + iconData = MihIcons.facebook; btnColor = const Color(0xFF4267B2); break; case "reddit": - iconData = FontAwesomeIcons.reddit; + iconData = MihIcons.reddit; btnColor = const Color(0xFFFF4500); break; case "discord": - iconData = FontAwesomeIcons.discord; + iconData = MihIcons.discord; btnColor = const Color(0xFF5865F2); break; case "git": - iconData = FontAwesomeIcons.git; - btnColor = const Color(0xFF73A952); + iconData = MihIcons.git; + btnColor = const Color(0xFFf14e32); + break; + case "telegram": + iconData = MihIcons.telegram; + btnColor = const Color(0xFF0088cc); + break; + case "pinterest": + iconData = MihIcons.pinterest; + btnColor = const Color(0xFFe60023); + break; + case "snapchat": + iconData = MihIcons.snapchat; + btnColor = const Color(0xFFfffc00); + iconColor = Colors.black; + break; + case "messenger": + iconData = MihIcons.messenger; + btnColor = const Color(0xFF0084ff); + break; + case "medium": + iconData = MihIcons.medium; + btnColor = const Color(0xFF000000); + break; + case "substack": + iconData = MihIcons.substack; + btnColor = const Color(0xFFFF7731); + break; + case "spotify": + iconData = MihIcons.spotify; + btnColor = const Color(0xFF1db954); + iconColor = Colors.black; + break; + case "yt music": + iconData = MihIcons.youtubeMusic; + btnColor = const Color(0xFFFF0000); + iconColor = Colors.white; + break; + case "apple music": + iconData = MihIcons.appleMusic; + btnColor = const Color(0xFFff4e6b); + break; + case "patreon": + iconData = MihIcons.patreon; + btnColor = const Color(0xFF000000); + break; + case "loolio": + iconData = MihIcons.loolio; + btnColor = const Color(0xFF24244a); + iconColor = const Color(0xFF5fc343); + break; + case "wechat": + iconData = MihIcons.wechat; + btnColor = const Color(0xFFff4e6b); break; default: - iconData = FontAwesomeIcons.link; + // iconData = FontAwesomeIcons.link; + iconData = MihIcons.link; btnColor = MihColors.secondary(); - iconColor = Colors.black; + iconColor = MihColors.primary(); } - return MihButton( - width: widget.buttonSize ?? 70, - height: widget.buttonSize ?? 70, - onPressed: () { - launchSocialUrl(Uri.parse(link.web_link)); - }, - buttonColor: btnColor, - child: FaIcon( - iconData, - color: iconColor, - size: 40, - ), + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + MihButton( + width: widget.buttonSize ?? 70, + height: widget.buttonSize ?? 70, + onPressed: () { + launchSocialUrl(Uri.parse(link.destination)); + }, + buttonColor: btnColor, + child: Icon( + iconData, + color: iconColor, + size: 50, + ), + ), + const SizedBox(height: 2), + if (link.custom_name.isNotEmpty) + Text( + link.custom_name, + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + // link.custom_name.isNotEmpty + // ? Text(link.custom_name) + // : Text(link.site_name), + ], ); // return MihPackageTile( // onTap: () { @@ -137,6 +207,7 @@ class _MihProfileLinksState extends State { children: [ Wrap( alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, runSpacing: 10, spacing: 10, children: widget.links.map( diff --git a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart index dec6e168..10449235 100644 --- a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart +++ b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart @@ -725,79 +725,101 @@ class _MihInfoState extends State { idprofile_links: 1, app_id: "1234", business_id: "", - destination: "Youtube", - web_link: "https://www.youtube.com/@MzansiInnovationHub", + site_name: "Youtube", + custom_name: "", + destination: "https://www.youtube.com/@MzansiInnovationHub", + order: 1, ), ProfileLink( idprofile_links: 1, app_id: "1234", business_id: "", - destination: "TikTok", - web_link: "https://www.tiktok.com/@mzansiinnovationhub", + site_name: "TikTok", + custom_name: "", + destination: "https://www.tiktok.com/@mzansiinnovationhub", + order: 2, ), ProfileLink( idprofile_links: 1, app_id: "1234", business_id: "", - destination: "Twitch", - web_link: "https://www.twitch.tv/mzansiinnovationhub", + site_name: "Twitch", + custom_name: "", + destination: "https://www.twitch.tv/mzansiinnovationhub", + order: 3, ), ProfileLink( idprofile_links: 1, app_id: "1234", business_id: "", - destination: "Threads", - web_link: "https://www.threads.com/@mzansi.innovation.hub", + site_name: "Threads", + custom_name: "", + destination: "https://www.threads.com/@mzansi.innovation.hub", + order: 4, ), ProfileLink( idprofile_links: 1, app_id: "1234", business_id: "", - destination: "WhatsApp", - web_link: "https://whatsapp.com/channel/0029Vax3INCIyPtMn8KgeM2F", + site_name: "WhatsApp", + custom_name: "", + destination: "https://whatsapp.com/channel/0029Vax3INCIyPtMn8KgeM2F", + order: 5, ), ProfileLink( idprofile_links: 1, app_id: "1234", business_id: "", - destination: "Instagram", - web_link: "https://www.instagram.com/mzansi.innovation.hub/", + site_name: "Instagram", + custom_name: "", + destination: "https://www.instagram.com/mzansi.innovation.hub/", + order: 6, ), ProfileLink( idprofile_links: 1, app_id: "1234", business_id: "", - destination: "X", - web_link: "https://x.com/mzansi_inno_hub", + site_name: "X", + custom_name: "", + destination: "https://x.com/mzansi_inno_hub", + order: 7, ), ProfileLink( idprofile_links: 1, app_id: "1234", business_id: "", - destination: "LinkedIn", - web_link: "https://www.linkedin.com/company/mzansi-innovation-hub/", + site_name: "LinkedIn", + custom_name: "", + destination: "https://www.linkedin.com/company/mzansi-innovation-hub/", + order: 8, ), ProfileLink( idprofile_links: 1, app_id: "1234", business_id: "", - destination: "Facebook", - web_link: "https://www.facebook.com/profile.php?id=61565345762136", + site_name: "Facebook", + custom_name: "", + destination: "https://www.facebook.com/profile.php?id=61565345762136", + order: 9, ), ProfileLink( idprofile_links: 1, app_id: "1234", business_id: "", - destination: "Reddit", - web_link: "https://www.reddit.com/r/Mzani_Innovation_Hub/", + site_name: "Reddit", + custom_name: "", + destination: "https://www.reddit.com/r/Mzani_Innovation_Hub/", + order: 10, ), ProfileLink( idprofile_links: 1, app_id: "1234", business_id: "", - destination: "Git", - web_link: + site_name: "Git", + custom_name: "", + destination: "https://git.mzansi-innovation-hub.co.za/yaso_meth/mih-project", + order: 11, ), ]; return Column( diff --git a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart index 920f2768..0cd4f7d8 100644 --- a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart +++ b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart @@ -130,7 +130,7 @@ class _MihMineSweeperLeaderBoardState extends State { children: [ const SizedBox(height: 50), Icon( - MihIcons.mineSweeper, + MihIcons.mihMinesweeper, size: 165, color: MihColors.secondary(), ), diff --git a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart index 0d785f14..9e3c2c8f 100644 --- a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart +++ b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart @@ -596,7 +596,7 @@ class _MineSweeperGameState extends State { children: [ const SizedBox(height: 50), Icon( - MihIcons.mineSweeper, + MihIcons.mihMinesweeper, size: 165, color: MihColors.secondary(), ), @@ -780,7 +780,7 @@ class _MineSweeperGameState extends State { _timer != null && !kIsWeb && (Platform.isAndroid || Platform.isIOS) ? MihBannerAd() : SizedBox(), - SizedBox(height: 15), + SizedBox(height: 10), ], ); }, diff --git a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart index c0adf641..6b14c8c2 100644 --- a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart +++ b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart @@ -134,7 +134,7 @@ class _MihMineSweeperLeaderBoardState extends State { children: [ const SizedBox(height: 50), Icon( - MihIcons.mineSweeper, + MihIcons.mihMinesweeper, size: 165, color: MihColors.secondary(), ), diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile_view.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile_view.dart index 8f48de6f..92a0910c 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile_view.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/mzansi_business_profile_view.dart @@ -40,7 +40,7 @@ class _MzansiBusinessProfileViewState extends State { extra: true, ); } else { - KenLogger.success("Business found: ${biz.Name}"); + // KenLogger.success("Business found: ${biz.Name}"); directoryProvider.setSelectedBusiness(business: biz); } } diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart index e2d8a6e6..6bffdb4a 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart @@ -1,9 +1,13 @@ +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:custom_rating_bar/custom_rating_bar.dart'; import 'package:file_picker/file_picker.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:mih_package_toolkit/mih_package_toolkit.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_banner_ad.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_business_info_card_v2.dart'; import 'package:mzansi_innovation_hub/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; @@ -53,136 +57,142 @@ class _MihBusinessDetailsViewState extends State { return Consumer( builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, Widget? child) { - return Stack( + return Column( children: [ - MihSingleChildScroll( - scrollbarOn: true, - child: Padding( - padding: MzansiInnovationHub.of(context)!.theme.screenType == - "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.2) - : EdgeInsets.symmetric(horizontal: width * 0), - child: Column( - children: [ - FutureBuilder( - future: futureImageUrl, - builder: (context, asyncSnapshot) { - if (asyncSnapshot.connectionState == - ConnectionState.done && - asyncSnapshot.hasData) { - if (asyncSnapshot.requireData != "") { - return MihCircleAvatar( - imageFile: CachedNetworkImageProvider( - asyncSnapshot.requireData), - width: profilePictureWidth, - expandable: true, - editable: false, - fileNameController: TextEditingController(), - userSelectedfile: file, - frameColor: MihColors.secondary(), - backgroundColor: MihColors.primary(), - onChange: () {}, - ); + Expanded( + child: MihSingleChildScroll( + scrollbarOn: true, + child: Padding( + padding: MzansiInnovationHub.of(context)!.theme.screenType == + "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0), + child: Column( + children: [ + FutureBuilder( + future: futureImageUrl, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == + ConnectionState.done && + asyncSnapshot.hasData) { + if (asyncSnapshot.requireData != "") { + return MihCircleAvatar( + imageFile: CachedNetworkImageProvider( + asyncSnapshot.requireData), + width: profilePictureWidth, + expandable: true, + editable: false, + fileNameController: TextEditingController(), + userSelectedfile: file, + frameColor: MihColors.secondary(), + backgroundColor: MihColors.primary(), + onChange: () {}, + ); + } else { + return Icon( + MihIcons.iDontKnow, + size: profilePictureWidth, + color: MihColors.secondary(), + ); + } } else { return Icon( - MihIcons.iDontKnow, + MihIcons.mihRing, size: profilePictureWidth, color: MihColors.secondary(), ); } - } else { - return Icon( - MihIcons.mihRing, - size: profilePictureWidth, - color: MihColors.secondary(), - ); - } - }), - // Center( - // child: MihCircleAvatar( - // imageFile: widget.logoImage, - // width: 150, - // editable: false, - // fileNameController: fileNameController, - // userSelectedfile: imageFile, - // frameColor: - // MihColors.secondary(), - // backgroundColor: - // MihColors.primary(), - // onChange: (selectedfile) { - // setState(() { - // imageFile = selectedfile; - // }); - // }, - // ), - // ), - FittedBox( - child: Text( - directoryProvider.selectedBusiness!.Name, - style: TextStyle( - fontSize: 35, - fontWeight: FontWeight.bold, - color: MihColors.secondary(), - ), - ), - ), - FittedBox( - child: Text( - directoryProvider.selectedBusiness!.type, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w600, - color: MihColors.secondary(), - ), - ), - ), - RatingBar.readOnly( - size: 50, - alignment: Alignment.center, - filledIcon: Icons.star, - emptyIcon: Icons.star_border, - halfFilledIcon: Icons.star_half, - filledColor: MihColors.yellow(), - // MihColors.primary(), - emptyColor: MihColors.secondary(), - halfFilledColor: MihColors.yellow(), - // MihColors.primary(), - isHalfAllowed: true, - initialRating: - directoryProvider.selectedBusiness!.rating.isNotEmpty - ? double.parse( - directoryProvider.selectedBusiness!.rating) - : 0, - maxRating: 5, - ), - const SizedBox(height: 5), - Center( - child: SizedBox( - width: 700, + }), + // Center( + // child: MihCircleAvatar( + // imageFile: widget.logoImage, + // width: 150, + // editable: false, + // fileNameController: fileNameController, + // userSelectedfile: imageFile, + // frameColor: + // MihColors.secondary(), + // backgroundColor: + // MihColors.primary(), + // onChange: (selectedfile) { + // setState(() { + // imageFile = selectedfile; + // }); + // }, + // ), + // ), + FittedBox( child: Text( - directoryProvider - .selectedBusiness!.mission_vision.isNotEmpty - ? directoryProvider - .selectedBusiness!.mission_vision - : "No Mission & Vision added yet", - textAlign: TextAlign.center, + directoryProvider.selectedBusiness!.Name, style: TextStyle( - fontSize: 15, + fontSize: 35, fontWeight: FontWeight.bold, color: MihColors.secondary(), ), ), ), - ), - const SizedBox(height: 20), - MihBusinessCardV2( - business: directoryProvider.selectedBusiness!, - width: width, - ), - ], + FittedBox( + child: Text( + directoryProvider.selectedBusiness!.type, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: MihColors.secondary(), + ), + ), + ), + RatingBar.readOnly( + size: 50, + alignment: Alignment.center, + filledIcon: Icons.star, + emptyIcon: Icons.star_border, + halfFilledIcon: Icons.star_half, + filledColor: MihColors.yellow(), + // MihColors.primary(), + emptyColor: MihColors.secondary(), + halfFilledColor: MihColors.yellow(), + // MihColors.primary(), + isHalfAllowed: true, + initialRating: directoryProvider + .selectedBusiness!.rating.isNotEmpty + ? double.parse( + directoryProvider.selectedBusiness!.rating) + : 0, + maxRating: 5, + ), + const SizedBox(height: 5), + Center( + child: SizedBox( + width: 700, + child: Text( + directoryProvider + .selectedBusiness!.mission_vision.isNotEmpty + ? directoryProvider + .selectedBusiness!.mission_vision + : "No Mission & Vision added yet", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: MihColors.secondary(), + ), + ), + ), + ), + const SizedBox(height: 20), + MihBusinessCardV2( + business: directoryProvider.selectedBusiness!, + width: width, + ), + ], + ), ), ), ), + !kIsWeb && (Platform.isAndroid || Platform.isIOS) + ? MihBannerAd() + : SizedBox(), + SizedBox(height: 10), ], ); }, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart index 491040e6..0977e2dc 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart @@ -63,7 +63,7 @@ class _MihBusinessQrCodeState extends State { Future saveImage(Uint8List imageBytes) async { final String filename = - "${business.Name}_QR_Code_${DateTime.now().millisecondsSinceEpoch}.png"; + "${business.Name}_QR_Code_${DateTime.now().millisecondsSinceEpoch}"; if (kIsWeb) { await FileSaver.instance.saveFile( name: filename, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_add_user_profile_links_window.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_add_user_profile_links_window.dart new file mode 100644 index 00000000..74651ccc --- /dev/null +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_add_user_profile_links_window.dart @@ -0,0 +1,185 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; +import 'package:mih_package_toolkit/mih_package_toolkit.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_profile_links_service.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; + +class MihAddUserProfileLinksWindow extends StatefulWidget { + const MihAddUserProfileLinksWindow({super.key}); + + @override + State createState() => + _MihAddUserProfileLinksWindowState(); +} + +class _MihAddUserProfileLinksWindowState + extends State { + final _formKey = GlobalKey(); + List _dropdowOptions = [ + "YouTube", + "TikTok", + "Twitch", + "Threads", + "WhatsApp", + "Instagram", + "X", + "LinkedIn", + "Facebook", + "Reddit", + "Discord", + "Git", + "Telegram", + "Pinterest", + "Snapchat", + "Messenger", + "Medium", + "Substack", + "Spotify", + "YT Music", + "Apple Music", + "Patreon", + "Loolio", + "WeChat", + "Other" + ]; + TextEditingController _dropdownLinkNameController = TextEditingController(); + TextEditingController _linkNameController = TextEditingController(); + TextEditingController _destinationController = TextEditingController(); + + void successPopUp(String title, String message, int packageIndex) { + MihAlertServices().successBasicAlert( + title, + message, + context, + ); + } + + @override + Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + _dropdowOptions.sort(); + bool isOtherSelected = _dropdownLinkNameController.text == "Other"; + return Consumer( + builder: ( + BuildContext context, + MzansiProfileProvider profileProvider, + Widget? child, + ) { + return MihPackageWindow( + fullscreen: false, + windowTitle: "Add Link", + onWindowTapClose: () { + _dropdownLinkNameController.clear(); + _destinationController.clear(); + _linkNameController.clear(); + Navigator.pop(context); + }, + windowBody: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: screenWidth * 0.05) + : EdgeInsets.symmetric(horizontal: screenWidth * 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihDropdownField( + controller: _dropdownLinkNameController, + hintText: 'Site Name', + dropdownOptions: _dropdowOptions, + requiredText: true, + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + onSelected: (value) { + setState(() {}); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.secondary(), + inputColor: MihColors.primary(), + controller: _linkNameController, + hintText: "Custom Name", + requiredText: isOtherSelected, + validator: (value) { + if (isOtherSelected) { + return MihValidationServices().isEmpty(value); + } + return null; + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.secondary(), + inputColor: MihColors.primary(), + controller: _destinationController, + hintText: "Link", + requiredText: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 20), + MihButton( + onPressed: () async { + if (_formKey.currentState!.validate()) { + MihProfileLinksServices.loadingPopUp(context); + int statusCode = + await MihProfileLinksServices.addProfileLink( + profileProvider, + profileProvider.user!.app_id, + "", + _dropdownLinkNameController.text, + _linkNameController.text, + _destinationController.text, + profileProvider.personalLinks.length + 1, + ); + KenLogger.success("Status COde: $statusCode"); + context.pop(); + if (statusCode == 201) { + await MihProfileLinksServices.getUserProfileLinks( + profileProvider, + profileProvider.user!.app_id, + ); + context.pop(); + successPopUp( + "Profile Link Added", + "You have successfully added a new link to your profile", + 0); + } else { + MihAlertServices().internetConnectionAlert(context); + } + } else { + MihAlertServices().inputErrorAlert(context); + } + }, + buttonColor: MihColors.green(), + width: 300, + child: Text( + "Add", + style: TextStyle( + color: MihColors.primary(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_user_profile_links_window.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_user_profile_links_window.dart new file mode 100644 index 00000000..48bdf2a6 --- /dev/null +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_user_profile_links_window.dart @@ -0,0 +1,195 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; +import 'package:mih_package_toolkit/mih_package_toolkit.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_objects/profile_link.dart'; +import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_profile_links_service.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:provider/provider.dart'; + +class MihEditUserProfileLinksWindow extends StatefulWidget { + final ProfileLink link; + const MihEditUserProfileLinksWindow({ + super.key, + required this.link, + }); + + @override + State createState() => + _MihEditUserProfileLinksWindowState(); +} + +class _MihEditUserProfileLinksWindowState + extends State { + final _formKey = GlobalKey(); + List _dropdowOptions = [ + "YouTube", + "TikTok", + "Twitch", + "Threads", + "WhatsApp", + "Instagram", + "X", + "LinkedIn", + "Facebook", + "Reddit", + "Discord", + "Git", + "Telegram", + "Pinterest", + "Snapchat", + "Messenger", + "Medium", + "Substack", + "Spotify", + "YT Music", + "Apple Music", + "Patreon", + "Loolio", + "WeChat", + "Other" + ]; + TextEditingController _dropdownLinkNameController = TextEditingController(); + TextEditingController _linkNameController = TextEditingController(); + TextEditingController _destinationController = TextEditingController(); + + void successPopUp(String title, String message, int packageIndex) { + MihAlertServices().successBasicAlert( + title, + message, + context, + ); + } + + @override + void initState() { + super.initState(); + _dropdownLinkNameController.text = widget.link.site_name; + _linkNameController.text = widget.link.custom_name; + _destinationController.text = widget.link.destination; + } + + @override + Widget build(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + _dropdowOptions.sort(); + bool isOtherSelected = _dropdownLinkNameController.text == "Other"; + return Consumer( + builder: ( + BuildContext context, + MzansiProfileProvider profileProvider, + Widget? child, + ) { + return MihPackageWindow( + fullscreen: false, + windowTitle: "Update Link", + onWindowTapClose: () { + _dropdownLinkNameController.clear(); + _destinationController.clear(); + _linkNameController.clear(); + Navigator.pop(context); + }, + windowBody: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: screenWidth * 0.05) + : EdgeInsets.symmetric(horizontal: screenWidth * 0), + child: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihDropdownField( + controller: _dropdownLinkNameController, + hintText: 'Site Name', + dropdownOptions: _dropdowOptions, + requiredText: true, + editable: true, + enableSearch: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + onSelected: (value) { + setState(() {}); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.secondary(), + inputColor: MihColors.primary(), + controller: _linkNameController, + hintText: "Custom Name", + requiredText: isOtherSelected, + validator: (value) { + if (isOtherSelected) { + return MihValidationServices().isEmpty(value); + } + return null; + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.secondary(), + inputColor: MihColors.primary(), + controller: _destinationController, + hintText: "Link", + requiredText: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 20), + MihButton( + onPressed: () async { + if (_formKey.currentState!.validate()) { + MihProfileLinksServices.loadingPopUp(context); + int statusCode = + await MihProfileLinksServices.updateProfileLink( + profileProvider, + widget.link.idprofile_links, + profileProvider.user!.app_id, + "", + _dropdownLinkNameController.text, + _linkNameController.text, + _destinationController.text, + widget.link.order, + context, + ); + context.pop(); + if (statusCode == 200) { + context.pop(); + successPopUp( + "Profile Link Updated", + "You have successfully update a link in your profile", + 0); + } else { + MihAlertServices().internetConnectionAlert(context); + } + } else { + MihAlertServices().inputErrorAlert(context); + } + }, + buttonColor: MihColors.green(), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MihColors.primary(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_manage_user_profile_links_window.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_manage_user_profile_links_window.dart new file mode 100644 index 00000000..496c870a --- /dev/null +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_manage_user_profile_links_window.dart @@ -0,0 +1,226 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mih_package_toolkit/mih_package_toolkit.dart'; +import 'package:mzansi_innovation_hub/mih_objects/profile_link.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/components/mih_edit_user_profile_links_window.dart'; +import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_profile_links_service.dart'; +import 'package:provider/provider.dart'; + +class MihManageUserProfileLinksWindow extends StatefulWidget { + const MihManageUserProfileLinksWindow({super.key}); + + @override + State createState() => + _MihManageUserProfileLinksWindowState(); +} + +class _MihManageUserProfileLinksWindowState + extends State { + void successPopUp(String title, String message, int packageIndex) { + MihAlertServices().successBasicAlert( + title, + message, + context, + ); + } + + void removeLinkWarning( + MzansiProfileProvider profileProvider, int idprofile_links) { + MihAlertServices().warningAdvancedAlert( + "Remove Link?", + "Are you sure you want to remove this link from your profile?", + [ + MihButton( + onPressed: () async { + MihProfileLinksServices.loadingPopUp(context); + int statusCode = await MihProfileLinksServices.deleteProfileLink( + profileProvider, + idprofile_links, + ); + context.pop(); + context.pop(); + if (statusCode == 200) { + successPopUp("profile Link Deleted", + "you have successfully deleted a link to your profile", 0); + } else { + MihAlertServices().internetConnectionAlert(context); + } + }, + buttonColor: MihColors.red(), + width: 300, + child: Text( + "Remove", + style: TextStyle( + color: MihColors.primary(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + MihButton( + onPressed: () async { + context.pop(); + }, + buttonColor: MihColors.green(), + width: 300, + child: Text( + "Cancel", + style: TextStyle( + color: MihColors.primary(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + context, + ); + } + + void editLinkWindow(ProfileLink link) { + showDialog( + context: context, + builder: (context) => MihEditUserProfileLinksWindow(link: link)); + } + + Widget linkActions(MzansiProfileProvider profileProvider, ProfileLink link) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + color: MihColors.green(), + onPressed: () { + editLinkWindow(link); + }, + icon: Icon( + Icons.edit, + ), + ), + const SizedBox(width: 2), + IconButton( + color: MihColors.red(), + onPressed: () { + removeLinkWarning(profileProvider, link.idprofile_links); + }, + icon: Icon( + Icons.delete, + ), + ), + ], + ); + } + + @override + Widget build(BuildContext context) { + // double screenWidth = MediaQuery.of(context).size.width; + return Consumer( + builder: ( + BuildContext context, + MzansiProfileProvider profileProvider, + Widget? child, + ) { + // return Placeholder(); + return MihPackageWindow( + fullscreen: true, + windowTitle: "Manage Links", + onWindowTapClose: () { + Navigator.pop(context); + }, + windowBody: Column( + children: [ + Expanded( + child: Theme( + data: Theme.of(context).copyWith( + iconTheme: IconThemeData( + color: MihColors.grey(), + ), + ), + child: ReorderableListView.builder( + itemBuilder: (context, index) { + ProfileLink link = profileProvider.personalLinks[index]; + String display = link.site_name; + if (link.custom_name.isNotEmpty) { + display += " (${link.custom_name})"; + } + return ListTile( + key: ValueKey("$index"), + title: Text( + "$display", + style: TextStyle( + // fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + leading: linkActions( + profileProvider, + link, + ), + ); + }, + itemCount: profileProvider.personalLinks.length, + onReorder: (oldIndex, newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; + } + final ProfileLink link = + profileProvider.personalLinks.removeAt(oldIndex); + profileProvider.personalLinks.insert(newIndex, link); + }), + ), + ), + MihButton( + onPressed: () async { + MihProfileLinksServices.loadingPopUp(context); + int newIndex = 1; + for (var link in profileProvider.personalLinks) { + int statusCode = + await MihProfileLinksServices.updateProfileLink( + profileProvider, + link.idprofile_links, + link.app_id, + link.business_id, + link.site_name, + link.custom_name, + link.destination, + newIndex, + context); + if (statusCode != 200) { + await MihProfileLinksServices.updateProfileLink( + profileProvider, + link.idprofile_links, + link.app_id, + link.business_id, + link.site_name, + link.custom_name, + link.destination, + newIndex, + context); + } + newIndex++; + } + context.pop(); + context.pop(); + successPopUp("profile Link Reordered", + "you have successfully reordered your profile links", 0); + }, + buttonColor: MihColors.green(), + width: 300, + child: Text( + "Update Order", + style: TextStyle( + color: MihColors.primary(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 10), + ], + ), + ); + }, + ); + } +} diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart index 7a8e7174..b399391d 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile.dart @@ -1,10 +1,12 @@ import 'package:go_router/go_router.dart'; import 'package:mih_package_toolkit/mih_package_toolkit.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_qr_code.dart'; import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_data_helper_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_profile_links_service.dart'; import 'package:provider/provider.dart'; class MzansiProfile extends StatefulWidget { @@ -19,6 +21,7 @@ class MzansiProfile extends StatefulWidget { class _MzansiProfileState extends State { bool _isLoadingInitialData = true; late final MihPersonalProfile _personalProfile; + late final MihPersonalQrCode _personalQrCode; late final MihPersonalSettings _personalSettings; Future _loadInitialData() async { @@ -32,6 +35,10 @@ class _MzansiProfileState extends State { mzansiProfileProvider, ); } + await MihProfileLinksServices.getUserProfileLinks( + mzansiProfileProvider, + mzansiProfileProvider.user!.app_id, + ); setState(() { _isLoadingInitialData = false; }); @@ -41,6 +48,7 @@ class _MzansiProfileState extends State { void initState() { super.initState(); _personalProfile = const MihPersonalProfile(); + _personalQrCode = const MihPersonalQrCode(user: null); _personalSettings = const MihPersonalSettings(); _loadInitialData(); } @@ -91,12 +99,12 @@ class _MzansiProfileState extends State { temp[const Icon(Icons.person)] = () { context.read().setPersonalIndex(0); }; - // temp[const Icon(Icons.person)] = () { - // context.read().setPersonalIndex(1); - // }; - temp[const Icon(Icons.settings)] = () { + temp[const Icon(Icons.qr_code_rounded)] = () { context.read().setPersonalIndex(1); }; + temp[const Icon(Icons.settings)] = () { + context.read().setPersonalIndex(2); + }; return MihPackageTools( tools: temp, selectedIndex: context.watch().personalIndex, @@ -106,6 +114,7 @@ class _MzansiProfileState extends State { List getToolBody() { return [ _personalProfile, + _personalQrCode, _personalSettings, ]; } @@ -113,6 +122,7 @@ class _MzansiProfileState extends State { List getToolTitle() { List toolTitles = [ "Profile", + "Share", "Settings", ]; return toolTitles; diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart index 1ba2d071..97bb37b5 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/mzansi_profile_view.dart @@ -1,11 +1,18 @@ import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mih_package_toolkit/mih_package_toolkit.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_qr_code.dart'; +import 'package:mzansi_innovation_hub/mih_providers/mzansi_directory_provider.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_user_services.dart'; +import 'package:provider/provider.dart'; class MzansiProfileView extends StatefulWidget { + final String? username; const MzansiProfileView({ super.key, + required this.username, }); @override @@ -15,25 +22,60 @@ class MzansiProfileView extends StatefulWidget { class _MzansiProfileViewState extends State { int _selectedIndex = 0; late final MihPersonalProfileView _personalProfileView; + late final MihPersonalQrCode _personalQrCode; + + void _loadUserData() async { + MzansiDirectoryProvider directoryProvider = + context.read(); + if (widget.username != null) { + final user = await MihUserServices() + .getMIHUserDetailsByUsername(widget.username!, context); + if (user == null) { + context.goNamed( + 'mihHome', + extra: true, + ); + } else { + KenLogger.success("User found: ${user.username}"); + directoryProvider.setSelectedUser(user: user); + } + } + _personalProfileView = MihPersonalProfileView(); + _personalQrCode = MihPersonalQrCode(user: directoryProvider.selectedUser); + } @override void initState() { super.initState(); - _personalProfileView = MihPersonalProfileView(); + _loadUserData(); } @override Widget build(BuildContext context) { - return MihPackage( - packageActionButton: getAction(), - packageTools: getTools(), - packageToolBodies: getToolBody(), - packageToolTitles: getToolTitle(), - selectedBodyIndex: _selectedIndex, - onIndexChange: (newValue) { - setState(() { - _selectedIndex = newValue; - }); + return Consumer( + builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, + Widget? child) { + if (directoryProvider.selectedUser == null) { + KenLogger.warning("User is null, showing loading indicator"); + return Scaffold( + body: const Center( + child: Mihloadingcircle(), + ), + ); + } else { + return MihPackage( + packageActionButton: getAction(), + packageTools: getTools(), + packageToolBodies: getToolBody(), + packageToolTitles: getToolTitle(), + selectedBodyIndex: _selectedIndex, + onIndexChange: (newValue) { + setState(() { + _selectedIndex = newValue; + }); + }, + ); + } }, ); } @@ -57,6 +99,11 @@ class _MzansiProfileViewState extends State { _selectedIndex = 0; }); }; + temp[const Icon(Icons.qr_code_rounded)] = () { + setState(() { + _selectedIndex = 1; + }); + }; return MihPackageTools( tools: temp, selectedIndex: _selectedIndex, @@ -66,12 +113,14 @@ class _MzansiProfileViewState extends State { List getToolBody() { return [ _personalProfileView, + _personalQrCode, ]; } List getToolTitle() { List toolTitles = [ "Profile", + "Share", ]; return toolTitles; } diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart index 7b1103a9..33c79207 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart @@ -2,9 +2,10 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:mih_package_toolkit/mih_package_toolkit.dart'; import 'package:mzansi_innovation_hub/main.dart'; -import 'package:mzansi_innovation_hub/mih_objects/profile_link.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_profile_links.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/components/mih_add_user_profile_links_window.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/components/mih_manage_user_profile_links_window.dart'; import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart'; import 'package:provider/provider.dart'; @@ -20,107 +21,29 @@ class _MihPersonalProfileState extends State { TextEditingController proPicController = TextEditingController(); PlatformFile? newSelectedProPic; - void editProfileWindow(double width) { + void editProfileWindow() { showDialog( context: context, barrierDismissible: false, - builder: (context) => Consumer( - builder: (BuildContext context, - MzansiProfileProvider mzansiProfileProvider, Widget? child) { - return MihEditPersonalProfileWindow(); - }, - ), + builder: (context) => MihEditPersonalProfileWindow(), ); } - List getTempLinks() { - // return []; - return [ - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Youtube", - web_link: "https://www.youtube.com/@MzansiInnovationHub", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Threads", - web_link: "https://www.threads.com/@mzansi.innovation.hub", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "TikTok", - web_link: "https://www.tiktok.com/@mzansiinnovationhub", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "WhatsApp", - web_link: "https://whatsapp.com/channel/0029Vax3INCIyPtMn8KgeM2F", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Twitch", - web_link: "https://www.twitch.tv/mzansiinnovationhub", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Instagram", - web_link: "https://www.instagram.com/mzansi.innovation.hub/", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "X", - web_link: "https://x.com/mzansi_inno_hub", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "LinkedIn", - web_link: "https://www.linkedin.com/in/yasien-meth-172352108/", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Facebook", - web_link: "https://www.facebook.com/profile.php?id=61565345762136", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Reddit", - web_link: "https://www.reddit.com/r/Mzani_Innovation_Hub/", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "Discord", - web_link: "https://discord.gg/ZtTZYd5d", - ), - ProfileLink( - idprofile_links: 1, - app_id: "1234", - business_id: "", - destination: "My App", - web_link: "https://app.mzansi-innovation-hub.co.za/about", - ), - ]; + void addProfileLinksWindow() { + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => MihAddUserProfileLinksWindow(), + ); + } + + void editProfileLinksWindow() { + showDialog( + context: context, + // barrierDismissible: false, + // builder: (context) => Placeholder(), + builder: (context) => MihManageUserProfileLinksWindow(), + ); } @override @@ -176,7 +99,7 @@ class _MihPersonalProfileState extends State { right: 5, child: MihButton( onPressed: () { - editProfileWindow(width); + editProfileWindow(); }, buttonColor: MihColors.green(), width: 35, @@ -245,20 +168,20 @@ class _MihPersonalProfileState extends State { ), const SizedBox(height: 15.0), MihProfileLinks( - // links: mzansiProfileProvider.personalLinks, - links: getTempLinks(), + links: mzansiProfileProvider.personalLinks, ), - const SizedBox(height: 5.0), + const SizedBox(height: 8.0), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ MihButton( onPressed: () { - editProfileWindow(width); + addProfileLinksWindow(); }, buttonColor: MihColors.green(), - // width: mzansiProfileProvider.personalLinks.isNotEmpty ? 50 : null, - width: getTempLinks().isNotEmpty ? 50 : null, + width: mzansiProfileProvider.personalLinks.isNotEmpty + ? 50 + : null, height: 50, child: Row( mainAxisAlignment: MainAxisAlignment.center, @@ -268,8 +191,7 @@ class _MihPersonalProfileState extends State { Icons.add, color: MihColors.primary(), ), - // if (mzansiProfileProvider.personalLinks.isEmpty) - if (getTempLinks().isEmpty) + if (mzansiProfileProvider.personalLinks.isEmpty) Text( "Add Links", style: TextStyle( @@ -281,6 +203,19 @@ class _MihPersonalProfileState extends State { ], ), ), + const SizedBox(width: 8.0), + MihButton( + onPressed: () { + editProfileLinksWindow(); + }, + buttonColor: MihColors.green(), + width: 50, + height: 50, + child: Icon( + Icons.edit, + color: MihColors.primary(), + ), + ), ], ), const SizedBox(height: 20.0), diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart index 8f9102b2..53fbdfde 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart @@ -1,12 +1,20 @@ +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/foundation.dart'; import 'package:mih_package_toolkit/mih_package_toolkit.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_objects/profile_link.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_banner_ad.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_profile_links.dart'; import 'package:mzansi_innovation_hub/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_circle_avatar.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_profile_links_service.dart'; import 'package:provider/provider.dart'; +import 'package:redacted/redacted.dart'; class MihPersonalProfileView extends StatefulWidget { const MihPersonalProfileView({ @@ -19,6 +27,7 @@ class MihPersonalProfileView extends StatefulWidget { class _MihPersonalProfileViewState extends State { late Future futureImageUrl; + late Future> futureLinks; PlatformFile? file; @override @@ -33,6 +42,8 @@ class _MihPersonalProfileViewState extends State { context.read(); futureImageUrl = MihFileApi.getMinioFileUrl( directoryProvider.selectedUser!.pro_pic_path); + futureLinks = MihProfileLinksServices.getUserProfileLinksMD( + directoryProvider, directoryProvider.selectedUser!.app_id); } @override @@ -51,105 +62,153 @@ class _MihPersonalProfileViewState extends State { return Consumer( builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, Widget? child) { - return MihSingleChildScroll( - scrollbarOn: true, - 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: [ - FutureBuilder( - future: futureImageUrl, - builder: (context, asyncSnapshot) { - if (asyncSnapshot.connectionState == - ConnectionState.done && - asyncSnapshot.hasData) { - if (asyncSnapshot.requireData != "") { - return MihCircleAvatar( - imageFile: CachedNetworkImageProvider( - asyncSnapshot.requireData), - width: profilePictureWidth, - expandable: true, - editable: false, - fileNameController: TextEditingController(), - userSelectedfile: file, - frameColor: MihColors.secondary(), - backgroundColor: MihColors.primary(), - onChange: () {}, - ); - } else { - return Icon( - MihIcons.iDontKnow, - size: profilePictureWidth, + return Column( + children: [ + Expanded( + child: MihSingleChildScroll( + scrollbarOn: true, + 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: [ + FutureBuilder( + future: futureImageUrl, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == + ConnectionState.done && + asyncSnapshot.hasData) { + if (asyncSnapshot.requireData != "") { + return MihCircleAvatar( + imageFile: CachedNetworkImageProvider( + asyncSnapshot.requireData), + width: profilePictureWidth, + expandable: true, + editable: false, + fileNameController: TextEditingController(), + userSelectedfile: file, + frameColor: MihColors.secondary(), + backgroundColor: MihColors.primary(), + onChange: () {}, + ); + } else { + return Icon( + MihIcons.iDontKnow, + size: profilePictureWidth, + color: MihColors.secondary(), + ); + } + } else { + return Icon( + MihIcons.mihRing, + size: profilePictureWidth, + color: MihColors.secondary(), + ); + } + }), + FittedBox( + child: Text( + directoryProvider.selectedUser!.username.isNotEmpty + ? directoryProvider.selectedUser!.username + : "Username", + style: TextStyle( + fontSize: 35, + fontWeight: FontWeight.bold, color: MihColors.secondary(), - ); - } - } else { - return Icon( - MihIcons.mihRing, - size: profilePictureWidth, - color: MihColors.secondary(), - ); - } - }), - FittedBox( - child: Text( - directoryProvider.selectedUser!.username.isNotEmpty - ? directoryProvider.selectedUser!.username - : "Username", - style: TextStyle( - fontSize: 35, - fontWeight: FontWeight.bold, - color: MihColors.secondary(), - ), - ), - ), - FittedBox( - child: Text( - directoryProvider.selectedUser!.fname.isNotEmpty - ? "${directoryProvider.selectedUser!.fname} ${directoryProvider.selectedUser!.lname}" - : "Name Surname", - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.secondary(), - ), - ), - ), - FittedBox( - child: Text( - directoryProvider.selectedUser!.type.toUpperCase(), - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - color: MihColors.secondary(), - ), - ), - ), - const SizedBox(height: 10.0), - Center( - child: SizedBox( - width: 700, - child: Text( - directoryProvider.selectedUser!.purpose.isNotEmpty - ? directoryProvider.selectedUser!.purpose - : "No Personal Mission added yet", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - color: MihColors.secondary(), + ), + ), ), - ), + FittedBox( + child: Text( + directoryProvider.selectedUser!.fname.isNotEmpty + ? "${directoryProvider.selectedUser!.fname} ${directoryProvider.selectedUser!.lname}" + : "Name Surname", + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.secondary(), + ), + ), + ), + FittedBox( + child: Text( + directoryProvider.selectedUser!.type.toUpperCase(), + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: MihColors.secondary(), + ), + ), + ), + const SizedBox(height: 10.0), + Center( + child: SizedBox( + width: 700, + child: Text( + directoryProvider.selectedUser!.purpose.isNotEmpty + ? directoryProvider.selectedUser!.purpose + : "No Personal Mission added yet", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: MihColors.secondary(), + ), + ), + ), + ), + const SizedBox(height: 15.0), + FutureBuilder( + future: futureLinks, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == + ConnectionState.done && + asyncSnapshot.hasData) { + directoryProvider.setPersonalLinks( + personalLinks: asyncSnapshot.data!); + return MihProfileLinks( + links: directoryProvider.personalLinks, + ); + } else { + return Wrap( + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + runSpacing: 10, + spacing: 10, + children: [ + Container(width: 70, height: 70).redacted( + context: context, + redact: true, + ), + Container(width: 70, height: 70).redacted( + context: context, + redact: true, + ), + Container(width: 70, height: 70).redacted( + context: context, + redact: true, + ), + Container(width: 70, height: 70).redacted( + context: context, + redact: true, + ), + ], + ); + } + }), + ], ), ), - const SizedBox(height: 30.0), - ], + ), ), - ), + !kIsWeb && (Platform.isAndroid || Platform.isIOS) + ? MihBannerAd() + : SizedBox(), + SizedBox(height: 10), + ], ); }, ); diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_qr_code.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_qr_code.dart new file mode 100644 index 00000000..0c791cbd --- /dev/null +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_qr_code.dart @@ -0,0 +1,410 @@ +import 'dart:io'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:file_saver/file_saver.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +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:mih_package_toolkit/mih_package_toolkit.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; +import 'package:mzansi_innovation_hub/mih_providers/mzansi_directory_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_circle_avatar.dart'; +import 'package:provider/provider.dart'; +import 'package:screenshot/screenshot.dart'; +import 'package:share_plus/share_plus.dart'; +import 'package:supertokens_flutter/supertokens.dart'; + +class MihPersonalQrCode extends StatefulWidget { + final AppUser? user; + const MihPersonalQrCode({ + super.key, + required this.user, + }); + + @override + State createState() => _MihPersonalQrCodeState(); +} + +class _MihPersonalQrCodeState extends State { + late AppUser user; + late Future futureImageUrl; + PlatformFile? file; + int qrSize = 500; + ScreenshotController screenshotController = ScreenshotController(); + Uint8List? personalQRImageFile; + bool _isUserSignedIn = false; + final String _qrCodedata = + "${AppEnviroment.baseAppUrl}/mzansi-profile/view?username="; + + Future _checkUserSession() async { + final doesSessionExist = await SuperTokens.doesSessionExist(); + setState(() { + _isUserSignedIn = doesSessionExist; + }); + } + + String getQrCodeData(int qrSize) { + String color = + MihColors.primary().toARGB32().toRadixString(16).substring(2, 8); + // KenLogger.warning(color); + String bgColor = + MihColors.secondary().toARGB32().toRadixString(16).substring(2, 8); + // KenLogger.warning(bgColor); + String encodedData = Uri.encodeComponent("$_qrCodedata${user.username}"); + return "https://api.qrserver.com/v1/create-qr-code/?data=$encodedData&size=${qrSize}x$qrSize&bgcolor=$bgColor&color=$color"; + } + + Future saveImage(Uint8List imageBytes) async { + final String filename = + "${user.username}_QR_Code_${DateTime.now().millisecondsSinceEpoch}"; + // "${user.username}_QR_Code_${DateTime.now().millisecondsSinceEpoch}.png"; + if (kIsWeb) { + await FileSaver.instance.saveFile( + name: filename, + bytes: imageBytes, + fileExtension: "png", + mimeType: MimeType.png, + ); + } else if (defaultTargetPlatform == TargetPlatform.linux || + defaultTargetPlatform == TargetPlatform.windows) { + // Use File Picker to get a save path on Desktop + String? outputFile = await FilePicker.platform.saveFile( + dialogTitle: 'Please select where to save your QR Code:', + fileName: filename, + ); + if (outputFile != null) { + final file = File(outputFile); + await file.writeAsBytes(imageBytes); + KenLogger.success("Saved to $outputFile"); + } + } else { + await FileSaver.instance.saveAs( + name: filename, + bytes: imageBytes, + fileExtension: "png", + mimeType: MimeType.png, + ); + } + } + + Future downloadQrCode() async { + if (_isUserSignedIn) { + await screenshotController.capture().then((image) { + // KenLogger.success("Image Captured: $image"); + setState(() { + personalQRImageFile = image; + }); + }).catchError((onError) { + KenLogger.error(onError); + }); + // KenLogger.success("QR Code Image Captured : $businessQRImageFile"); + saveImage(personalQRImageFile!); + } else { + showSignInRequiredAlert(); + } + } + + void showSignInRequiredAlert() { + showDialog( + barrierDismissible: false, + context: context, + builder: (context) { + return MihPackageWindow( + fullscreen: false, + windowTitle: null, + onWindowTapClose: null, + windowBody: Column( + children: [ + Icon( + MihIcons.mihLogo, + size: 100, + color: MihColors.secondary(), + ), + Text( + "Let's Get Started", + textAlign: TextAlign.center, + style: TextStyle( + color: MihColors.primary(), + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 15), + Text( + "Ready to dive in to the world of MIH?\nSign in or create a free MIH account to unlock all the powerful features of the MIH app. It's quick and easy!", + style: TextStyle( + color: MihColors.secondary(), + fontSize: 15, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + context.goNamed( + 'mihHome', + extra: true, + ); + }, + buttonColor: MihColors.green(), + elevation: 10, + width: 300, + child: Text( + "Sign In/ Create Account", + style: TextStyle( + color: MihColors.primary(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + ), + ); + }, + ); + } + + Widget displayPersonalQRCode(double profilePictureWidth) { + return Screenshot( + controller: screenshotController, + child: Material( + color: MihColors.secondary().withValues(alpha: 0.6), + borderRadius: BorderRadius.circular(25), + elevation: 10, + shadowColor: Colors.black, + child: Container( + decoration: BoxDecoration( + color: MihColors.secondary(), + borderRadius: BorderRadius.circular(20), + ), + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + FutureBuilder( + future: futureImageUrl, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == + ConnectionState.done && + asyncSnapshot.hasData) { + if (asyncSnapshot.requireData != "" || + asyncSnapshot.requireData.isNotEmpty) { + return MihCircleAvatar( + imageFile: CachedNetworkImageProvider( + asyncSnapshot.requireData), + width: profilePictureWidth, + expandable: true, + editable: false, + fileNameController: TextEditingController(), + userSelectedfile: file, + frameColor: MihColors.primary(), + backgroundColor: MihColors.secondary(), + onChange: () {}, + ); + } else { + return Icon( + MihIcons.iDontKnow, + size: profilePictureWidth, + color: MihColors.primary(), + ); + } + } else { + return Icon( + MihIcons.mihRing, + size: profilePictureWidth, + color: MihColors.primary(), + ); + } + }, + ), + FittedBox( + child: Text( + user.username, + style: TextStyle( + fontSize: 35, + fontWeight: FontWeight.bold, + color: MihColors.primary(), + ), + ), + ), + FittedBox( + child: Text( + "${user.fname} ${user.lname}", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: MihColors.primary(), + ), + ), + ), + const SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FittedBox( + child: Text( + "Powered by MIH", + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w600, + color: MihColors.primary(), + ), + ), + ), + const SizedBox(width: 5), + Icon( + MihIcons.mihLogo, + size: 20, + color: MihColors.primary(), + ), + ], + ), + const SizedBox(height: 10), + SizedBox( + width: 300, + height: 300, + child: CachedNetworkImage( + imageUrl: getQrCodeData(qrSize.toInt()), + placeholder: (context, url) => FittedBox( + child: const Mihloadingcircle(), + ), + errorWidget: (context, url, error) => + const Icon(Icons.error), + ), + ), + const SizedBox(height: 10), + FittedBox( + child: Text( + "Scan & Connect", + style: TextStyle( + fontSize: 30, + fontWeight: FontWeight.bold, + color: MihColors.primary(), + ), + ), + ), + ], + )), + ), + ), + ); + } + + void shareMIHLink(BuildContext context, String message, String link) { + String shareText = "$message: $link"; + SharePlus.instance.share( + ShareParams(text: shareText), + ); + } + + @override + void initState() { + super.initState(); + MzansiProfileProvider profileProvider = + context.read(); + if (widget.user != null) { + user = widget.user!; + } else { + user = profileProvider.user!; + } + _checkUserSession(); + futureImageUrl = MihFileApi.getMinioFileUrl(user.pro_pic_path); + } + + @override + Widget build(BuildContext context) { + Size screenSize = MediaQuery.of(context).size; + return Consumer(builder: ( + BuildContext context, + MzansiDirectoryProvider directoryProvider, + Widget? child, + ) { + return MihPackageToolBody( + backgroundColor: MihColors.primary(), + borderOn: false, + innerHorizontalPadding: 10, + bodyItem: getBody(screenSize, context), + ); + }); + } + + Widget getBody(Size screenSize, BuildContext context) { + double profilePictureWidth = 150; + return Stack( + alignment: Alignment.topCenter, + children: [ + MihSingleChildScroll( + scrollbarOn: true, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15.0), + child: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: screenSize.width * 0.2) + : EdgeInsets.symmetric( + horizontal: screenSize.width * 0), //.075), + child: Padding( + padding: const EdgeInsets.only(top: 10.0), + child: displayPersonalQRCode(profilePictureWidth), + ), + ), + ), + ), + Positioned( + right: 10, + bottom: 10, + child: MihFloatingMenu( + animatedIcon: AnimatedIcons.menu_close, + children: [ + SpeedDialChild( + child: Icon( + Icons.download_rounded, + color: MihColors.primary(), + ), + label: "Download QR Code", + labelBackgroundColor: MihColors.green(), + labelStyle: TextStyle( + color: MihColors.primary(), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.green(), + onTap: () { + downloadQrCode(); + }, + ), + SpeedDialChild( + child: Icon( + Icons.share_rounded, + color: MihColors.primary(), + ), + label: "Share Profile", + labelBackgroundColor: MihColors.green(), + labelStyle: TextStyle( + color: MihColors.primary(), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.green(), + onTap: () { + shareMIHLink( + context, + "Check out ${user.username} on the MIH app's Mzansi Directory", + "$_qrCodedata${user.username}", + ); + }, + ), + ]), + ) + ], + ); + } +} diff --git a/mih_ui/lib/mih_providers/mzansi_ai_provider.dart b/mih_ui/lib/mih_providers/mzansi_ai_provider.dart index cbc8bc64..50d5422d 100644 --- a/mih_ui/lib/mih_providers/mzansi_ai_provider.dart +++ b/mih_ui/lib/mih_providers/mzansi_ai_provider.dart @@ -17,7 +17,8 @@ class MzansiAiProvider extends ChangeNotifier { }) { ollamaProvider = OllamaProvider( baseUrl: "${AppEnviroment.baseAiUrl}/api", - model: AppEnviroment.getEnv() == "Prod" ? "qwen3.5:9b" : "qwen3.5:0.8b", + model: + AppEnviroment.getEnv() == "Prod" ? "mzansiai:latest" : "qwen3.5:0.8b", think: false, // systemPrompt: "---INSTRUCTION START---\n" // // "Respond concisely. Do not include any tags or internal monologues./n" diff --git a/mih_ui/lib/mih_providers/mzansi_directory_provider.dart b/mih_ui/lib/mih_providers/mzansi_directory_provider.dart index a68795c7..81cef7ca 100644 --- a/mih_ui/lib/mih_providers/mzansi_directory_provider.dart +++ b/mih_ui/lib/mih_providers/mzansi_directory_provider.dart @@ -3,6 +3,7 @@ import 'package:geolocator/geolocator.dart'; import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/bookmarked_business.dart'; import 'package:mzansi_innovation_hub/mih_objects/business.dart'; +import 'package:mzansi_innovation_hub/mih_objects/profile_link.dart'; class MzansiDirectoryProvider extends ChangeNotifier { int toolIndex; @@ -20,6 +21,8 @@ class MzansiDirectoryProvider extends ChangeNotifier { AppUser? selectedUser; String searchTerm; String businessTypeFilter; + List personalLinks = []; + List businessLinks = []; MzansiDirectoryProvider({ this.toolIndex = 0, @@ -116,4 +119,14 @@ class MzansiDirectoryProvider extends ChangeNotifier { this.businessTypeFilter = businessTypeFilter; notifyListeners(); } + + void setPersonalLinks({required List personalLinks}) { + this.personalLinks = personalLinks; + notifyListeners(); + } + + void setBusinessLinks({required List businessLinks}) { + this.businessLinks = businessLinks; + notifyListeners(); + } } diff --git a/mih_ui/lib/mih_providers/mzansi_profile_provider.dart b/mih_ui/lib/mih_providers/mzansi_profile_provider.dart index c35483d8..22a197fe 100644 --- a/mih_ui/lib/mih_providers/mzansi_profile_provider.dart +++ b/mih_ui/lib/mih_providers/mzansi_profile_provider.dart @@ -25,6 +25,7 @@ class MzansiProfileProvider extends ChangeNotifier { List userSearchResults = []; bool hideBusinessUserDetails; List personalLinks = []; + List businessLinks = []; MzansiProfileProvider({ this.personalHome = true, @@ -156,4 +157,30 @@ class MzansiProfileProvider extends ChangeNotifier { this.personalLinks = personalLinks; notifyListeners(); } + + void setBusinessLinks({required List businessLinks}) { + this.businessLinks = businessLinks; + notifyListeners(); + } + + void deleteProfileLink({required int linkId}) { + personalLinks.removeWhere((link) => link.idprofile_links == linkId); + businessLinks.removeWhere((link) => link.idprofile_links == linkId); + notifyListeners(); + } + + void editProfileLink({required ProfileLink updatedLink}) { + int personalIndex = personalLinks.indexWhere( + (link) => link.idprofile_links == updatedLink.idprofile_links); + int businessIndex = businessLinks.indexWhere( + (link) => link.idprofile_links == updatedLink.idprofile_links); + + if (personalIndex != -1) { + personalLinks[personalIndex] = updatedLink; + } + if (businessIndex != -1) { + businessLinks[personalIndex] = updatedLink; + } + notifyListeners(); + } } diff --git a/mih_ui/lib/mih_services/mih_profile_links_service.dart b/mih_ui/lib/mih_services/mih_profile_links_service.dart new file mode 100644 index 00000000..4990074e --- /dev/null +++ b/mih_ui/lib/mih_services/mih_profile_links_service.dart @@ -0,0 +1,165 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:ken_logger/ken_logger.dart'; +import 'package:mih_package_toolkit/mih_package_toolkit.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; +import 'package:mzansi_innovation_hub/mih_objects/profile_link.dart'; +import 'package:mzansi_innovation_hub/mih_providers/mzansi_directory_provider.dart'; +import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart'; +import 'package:supertokens_flutter/http.dart' as http; + +class MihProfileLinksServices { + final baseAPI = AppEnviroment.baseApiUrl; + + static Future> getUserProfileLinksMD( + MzansiDirectoryProvider directoryProvider, + String app_id, + ) async { + final response = await http.get( + Uri.parse("${AppEnviroment.baseApiUrl}/profile-links/user/$app_id")); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List myLinks = + List.from(l.map((model) => ProfileLink.fromJson(model))); + return myLinks; + } else { + throw Exception('failed to fecth user profile links'); + } + } + + static Future getUserProfileLinks( + MzansiProfileProvider profileProvider, + String app_id, + ) async { + final response = await http.get( + Uri.parse("${AppEnviroment.baseApiUrl}/profile-links/user/$app_id")); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List myLinks = + List.from(l.map((model) => ProfileLink.fromJson(model))); + profileProvider.setPersonalLinks(personalLinks: myLinks); + } else { + throw Exception('failed to fecth user profile links'); + } + } + + static Future getBusinessProfileLinks( + MzansiProfileProvider profileProvider, + String business_id, + ) async { + final response = await http.get(Uri.parse( + "${AppEnviroment.baseApiUrl}/profile-links/business/$business_id")); + if (response.statusCode == 200) { + Iterable l = jsonDecode(response.body); + List myLinks = + List.from(l.map((model) => ProfileLink.fromJson(model))); + profileProvider.setBusinessLinks(businessLinks: myLinks); + } else { + throw Exception('failed to fecth user profile links'); + } + } + + static Future deleteProfileLink( + MzansiProfileProvider profileProvider, + int idprofile_links, + ) async { + final response = await http.delete( + Uri.parse("${AppEnviroment.baseApiUrl}/profile-links/delete/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode( + { + "idprofile_links": idprofile_links, + }, + ), + ); + if (response.statusCode == 200) { + profileProvider.deleteProfileLink(linkId: idprofile_links); + } + return response.statusCode; + } + + static Future addProfileLink( + MzansiProfileProvider profileProvider, + String app_id, + String business_id, + String site_name, + String custom_name, + String destination, + int order, + ) async { + var response = await http.post( + Uri.parse("${AppEnviroment.baseApiUrl}/profile-links/insert/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "app_id": app_id, + "business_id": business_id, + "site_name": site_name, + "custom_name": custom_name, + "destination": destination, + "order": order, + }), + ); + KenLogger.success("Response: $response.statusCode"); + // if (response.statusCode == 201) { + // if (app_id == "") { + // await getUserProfileLinks(profileProvider, app_id); + // } else { + // await getBusinessProfileLinks(profileProvider, business_id); + // } + // } + return response.statusCode; + } + + static Future updateProfileLink( + MzansiProfileProvider profileProvider, + int idprofile_links, + String app_id, + String business_id, + String site_name, + String custom_name, + String destination, + int order, + BuildContext context, + ) async { + final response = await http.put( + Uri.parse("${AppEnviroment.baseApiUrl}/profile-links/update/"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + body: jsonEncode({ + "idprofile_links": idprofile_links, + "site_name": site_name, + "custom_name": custom_name, + "destination": destination, + "order": order, + }), + ); + if (response.statusCode == 200) { + profileProvider.editProfileLink( + updatedLink: ProfileLink( + idprofile_links: idprofile_links, + app_id: app_id, + business_id: business_id, + site_name: site_name, + custom_name: custom_name, + destination: destination, + order: order, + ), + ); + } + return response.statusCode; + } + + static void loadingPopUp(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle(); + }, + ); + } +} diff --git a/mih_ui/lib/mih_services/mih_user_services.dart b/mih_ui/lib/mih_services/mih_user_services.dart index 6abf2e8c..666805fd 100644 --- a/mih_ui/lib/mih_services/mih_user_services.dart +++ b/mih_ui/lib/mih_services/mih_user_services.dart @@ -113,6 +113,25 @@ class MihUserServices { } } + Future getMIHUserDetailsByUsername( + String username, + BuildContext context, + ) async { + var response = await http.get( + Uri.parse("${AppEnviroment.baseApiUrl}/user/username/$username"), + headers: { + "Content-Type": "application/json; charset=UTF-8" + }, + ); + if (response.statusCode == 200) { + String body = response.body; + var jsonBody = jsonDecode(body); + return AppUser.fromJson(jsonBody); + } else { + return null; + } + } + Future getMyUserDetails( MzansiProfileProvider profileProvider, ) async { diff --git a/mih_ui/pubspec.lock b/mih_ui/pubspec.lock index 90f67804..14c8ae1f 100644 --- a/mih_ui/pubspec.lock +++ b/mih_ui/pubspec.lock @@ -1220,10 +1220,10 @@ packages: dependency: "direct main" description: name: mih_package_toolkit - sha256: "63e9ee80b0a3ca8b15a7172f924152e0528149cbe29c7751287a4d30b2d0671f" + sha256: "3d0dec0ae9471a37b8c6822419633643721b6b463f2b9b862233feefcec6e8a6" url: "https://pub.dev" source: hosted - version: "0.0.2" + version: "0.0.6" mime: dependency: transitive description: diff --git a/mih_ui/pubspec.yaml b/mih_ui/pubspec.yaml index a0026402..b4247da3 100644 --- a/mih_ui/pubspec.yaml +++ b/mih_ui/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: sdk: flutter flutter_dotenv: ^6.0.0 - mih_package_toolkit: ^0.0.2 + mih_package_toolkit: ^0.0.6 cupertino_icons: ^1.0.8 font_awesome_flutter: ^10.7.0 # firebase_core: ^4.4.0