diff --git a/Frontend/lib/mih_apis/mih_mzansi_wallet_apis.dart b/Frontend/lib/mih_apis/mih_mzansi_wallet_apis.dart index 9bf002bb..231309b1 100644 --- a/Frontend/lib/mih_apis/mih_mzansi_wallet_apis.dart +++ b/Frontend/lib/mih_apis/mih_mzansi_wallet_apis.dart @@ -145,6 +145,7 @@ class MIHMzansiWalletApis { String card_number, String favourite, int priority_index, + String nickname, int navIndex, BuildContext context, ) async { @@ -161,6 +162,7 @@ class MIHMzansiWalletApis { "card_number": card_number, "favourite": favourite, "priority_index": priority_index, + "nickname": nickname, }), ); if (response.statusCode == 201) { @@ -193,6 +195,8 @@ class MIHMzansiWalletApis { int idloyalty_cards, String favourite, int priority_index, + String nickname, + String card_number, int navIndex, BuildContext context, ) async { @@ -207,6 +211,8 @@ class MIHMzansiWalletApis { "idloyalty_cards": idloyalty_cards, "favourite": favourite, "priority_index": priority_index, + "nickname": nickname, + "card_number": card_number, }), ); //print("Here4"); diff --git a/Frontend/lib/mih_components/mih_package_components/mih_app_window.dart b/Frontend/lib/mih_components/mih_package_components/mih_app_window.dart index e7aed14b..09277548 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_app_window.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_app_window.dart @@ -61,7 +61,37 @@ class _MihAppWindowState extends State { height: 50, child: Row( children: [ - widget.windowTools != null ? widget.windowTools! : Container(), + Container( + // color: Colors.white, + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular(25), // Optional: rounds the corners + boxShadow: const [ + BoxShadow( + color: Color.fromARGB( + 60, 0, 0, 0), // 0.2 opacity = 51 in alpha (255 * 0.2) + spreadRadius: -5, + blurRadius: 5, + offset: Offset(0, 5), + ), + ], + ), + child: IconButton.filled( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all( + MzanziInnovationHub.of(context)!.theme.errorColor()), + ), + color: MzanziInnovationHub.of(context)!.theme.primaryColor(), + iconSize: 20, + onPressed: () { + widget.onWindowTapClose(); + }, + icon: const Icon( + Icons.close, + ), + ), + ), Expanded( child: Container( padding: EdgeInsets.symmetric(horizontal: 15), @@ -78,20 +108,7 @@ class _MihAppWindowState extends State { ), ), ), - Container( - // color: Colors.white, - alignment: Alignment.center, - child: IconButton( - iconSize: 35, - onPressed: () { - widget.onWindowTapClose(); - }, - icon: Icon( - Icons.close, - color: MzanziInnovationHub.of(context)!.theme.errorColor(), - ), - ), - ), + widget.windowTools != null ? widget.windowTools! : Container(), ], ), ); diff --git a/Frontend/lib/mih_objects/loyalty_card.dart b/Frontend/lib/mih_objects/loyalty_card.dart index daa368e7..5926ae2d 100644 --- a/Frontend/lib/mih_objects/loyalty_card.dart +++ b/Frontend/lib/mih_objects/loyalty_card.dart @@ -5,6 +5,7 @@ class MIHLoyaltyCard { final String card_number; final String favourite; final int priority_index; + final String nickname; const MIHLoyaltyCard({ required this.idloyalty_cards, @@ -13,6 +14,7 @@ class MIHLoyaltyCard { required this.card_number, required this.favourite, required this.priority_index, + required this.nickname, }); factory MIHLoyaltyCard.fromJson(Map json) { @@ -24,6 +26,7 @@ class MIHLoyaltyCard { "card_number": String card_number, "favourite": String favourite, "priority_index": int priority_index, + "nickname": String nickname, } => MIHLoyaltyCard( idloyalty_cards: idloyalty_cards, @@ -32,6 +35,7 @@ class MIHLoyaltyCard { card_number: card_number, favourite: favourite, priority_index: priority_index, + nickname: nickname, ), _ => throw const FormatException('Failed to load loyalty card objects'), }; diff --git a/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart b/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart index 1284d7dd..06656932 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart @@ -1,9 +1,15 @@ +import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_apis/mih_mzansi_wallet_apis.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_number_input.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_alert.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_app_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_delete_message.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_error_message.dart'; import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_card_display.dart'; @@ -29,8 +35,104 @@ class BuildLoyaltyCardList extends StatefulWidget { } class _BuildLoyaltyCardListState extends State { + final TextEditingController _nicknameController = TextEditingController(); + final TextEditingController _cardNumberController = TextEditingController(); late int _noFavourites; + void openscanner() async { + Navigator.of(context).pushNamed( + '/scanner', + arguments: _cardNumberController, + ); + } + + void editCardWindow(BuildContext ctxt, int index) { + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => MIHWindow( + fullscreen: false, + windowTitle: "Edit Loyalty Card", + windowTools: const [ + SizedBox(width: 35), + ], + onWindowTapClose: () { + _cardNumberController.clear(); + _nicknameController.clear(); + Navigator.pop(context); + }, + windowBody: [ + MIHTextField( + controller: _nicknameController, + hintText: "Card Title", + editable: true, + required: false, + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: MIHNumberField( + controller: _cardNumberController, + hintText: "Card Number", + editable: true, + required: true, + enableDecimal: false, + ), + ), + const SizedBox(width: 10), + MIHButton( + onTap: () async { + openscanner(); + }, + buttonText: "Scan", + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + textColor: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + ), + ], + ), + const SizedBox(height: 15), + SizedBox( + width: 300, + height: 50, + child: MIHButton( + onTap: () { + if (_cardNumberController.text == "") { + showDialog( + context: context, + builder: (context) { + return const MIHErrorMessage(errorType: "Input Error"); + }, + ); + } else { + MIHMzansiWalletApis.updateLoyaltyCardAPICall( + widget.signedInUser, + widget.cardList[index].idloyalty_cards, + widget.cardList[index].favourite, + widget.cardList[index].priority_index, + _nicknameController.text, + _cardNumberController.text, + 0, + ctxt, + ); + } + }, + buttonText: "Update", + buttonColor: + MzanziInnovationHub.of(context)!.theme.secondaryColor(), + textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(), + ), + ), + ], + ), + ); + } + void deleteCardWindow(BuildContext ctxt, int index) { showDialog( context: context, @@ -85,7 +187,9 @@ class _BuildLoyaltyCardListState extends State { widget.cardList[index].idloyalty_cards, "Yes", _noFavourites, - 0, + widget.cardList[index].nickname, + widget.cardList[index].card_number, + 1, ctxt, ); }, @@ -139,6 +243,8 @@ class _BuildLoyaltyCardListState extends State { widget.cardList[index].idloyalty_cards, "", 0, + widget.cardList[index].nickname, + widget.cardList[index].card_number, 0, ctxt, ); @@ -175,39 +281,93 @@ class _BuildLoyaltyCardListState extends State { windowTitle: widget.cardList[index].shop_name.toUpperCase(), windowTools: Row( children: [ - IconButton( - onPressed: () { - deleteCardWindow(context, index); - }, - icon: Icon( - Icons.delete, - color: MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - Visibility( - visible: widget.cardList[index].favourite == "", - child: IconButton( - onPressed: () { - addToFavCardWindow(context, index); - }, - icon: Icon( - Icons.favorite, - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), - ), - ), - Visibility( - visible: widget.cardList[index].favourite != "", - child: IconButton( - onPressed: () { - removeFromFavCardWindow(context, index); - }, - icon: Icon( - Icons.favorite_border, - color: - MzanziInnovationHub.of(context)!.theme.secondaryColor(), - ), + Padding( + padding: const EdgeInsets.only(top: 5.0), + child: MihFloatingMenu( + animatedIcon: AnimatedIcons.menu_close, + direction: SpeedDialDirection.down, + children: [ + SpeedDialChild( + child: widget.cardList[index].favourite == "" + ? Icon( + Icons.favorite, + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + ) + : Icon( + Icons.favorite_border, + color: MzanziInnovationHub.of(context)! + .theme + .primaryColor(), + ), + label: widget.cardList[index].favourite == "" + ? "Add to Favourite" + : "Remove from Favourite", + labelBackgroundColor: + MzanziInnovationHub.of(context)!.theme.successColor(), + labelStyle: TextStyle( + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + fontWeight: FontWeight.bold, + ), + backgroundColor: + MzanziInnovationHub.of(context)!.theme.successColor(), + onTap: () { + if (widget.cardList[index].favourite == "") { + addToFavCardWindow(context, index); + } else { + removeFromFavCardWindow(context, index); + } + }, + ), + SpeedDialChild( + child: Icon( + Icons.edit, + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + ), + label: "Edit Card Details", + labelBackgroundColor: + MzanziInnovationHub.of(context)!.theme.successColor(), + labelStyle: TextStyle( + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + fontWeight: FontWeight.bold, + ), + backgroundColor: + MzanziInnovationHub.of(context)!.theme.successColor(), + onTap: () { + setState(() { + _cardNumberController.text = + widget.cardList[index].card_number; + _nicknameController.text = + widget.cardList[index].nickname; + }); + editCardWindow(context, index); + }, + ), + SpeedDialChild( + child: Icon( + Icons.delete, + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + ), + label: "Delete Card", + labelBackgroundColor: + MzanziInnovationHub.of(context)!.theme.successColor(), + labelStyle: TextStyle( + color: + MzanziInnovationHub.of(context)!.theme.primaryColor(), + fontWeight: FontWeight.bold, + ), + backgroundColor: + MzanziInnovationHub.of(context)!.theme.successColor(), + onTap: () { + deleteCardWindow(context, index); + }, + ), + ], ), ), ], @@ -221,7 +381,10 @@ class _BuildLoyaltyCardListState extends State { Container( width: 500, child: MihCardDisplay( - shopName: widget.cardList[index].shop_name, height: 250), + shopName: widget.cardList[index].shop_name, + nickname: widget.cardList[index].nickname, + height: 250, + ), ), const SizedBox(height: 20), Container( @@ -326,7 +489,10 @@ class _BuildLoyaltyCardListState extends State { itemBuilder: (context, index) { return GestureDetector( child: MihCardDisplay( - shopName: widget.cardList[index].shop_name, height: 100), + shopName: widget.cardList[index].shop_name, + nickname: widget.cardList[index].nickname, + height: 100, + ), onTap: () { viewCardWindow(index); }, diff --git a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_card_display.dart b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_card_display.dart index 72135830..f69d9c8a 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/components/mih_card_display.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/components/mih_card_display.dart @@ -2,11 +2,13 @@ import 'package:flutter/material.dart'; class MihCardDisplay extends StatefulWidget { final String shopName; + final String nickname; final double height; const MihCardDisplay({ super.key, required this.shopName, required this.height, + required this.nickname, }); @override @@ -155,6 +157,19 @@ class _MihCardDisplayState extends State { @override Widget build(BuildContext context) { - return displayLoyaltyCard(); + return Column( + children: [ + displayLoyaltyCard(), + FittedBox( + child: Text( + widget.nickname, + style: const TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + ) + ], + ); } } diff --git a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart index f7a2916e..5f0569e1 100644 --- a/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart +++ b/Frontend/lib/mih_packages/mzansi_wallet/package_tools/mih_cards.dart @@ -5,6 +5,7 @@ import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_ import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_number_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_search_input.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_layout/mih_window.dart'; import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih-app_tool_body.dart'; @@ -31,6 +32,7 @@ class MihCards extends StatefulWidget { class _MihCardsState extends State { final TextEditingController shopController = TextEditingController(); + final TextEditingController _nicknameController = TextEditingController(); final TextEditingController cardNumberController = TextEditingController(); final TextEditingController cardSearchController = TextEditingController(); late Future> cardList; @@ -97,6 +99,7 @@ class _MihCardsState extends State { onWindowTapClose: () { shopController.clear(); cardNumberController.clear(); + _nicknameController.clear(); shopName.value = ""; Navigator.pop(context); }, @@ -162,13 +165,21 @@ class _MihCardsState extends State { child: Column( children: [ const SizedBox(height: 10), - MihCardDisplay(shopName: shopName.value, height: 200), + MihCardDisplay( + shopName: shopName.value, nickname: "", height: 200), ], ), ); }, ), const SizedBox(height: 10), + MIHTextField( + controller: _nicknameController, + hintText: "Card Title", + editable: true, + required: false, + ), + const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -218,7 +229,8 @@ class _MihCardsState extends State { cardNumberController.text, "", 0, - 1, + _nicknameController.text, + 0, context, ); } @@ -242,6 +254,7 @@ class _MihCardsState extends State { cardSearchController.removeListener(searchShop); cardSearchController.dispose(); searchShopName.dispose(); + _nicknameController.dispose(); shopName.dispose(); super.dispose(); } @@ -332,7 +345,7 @@ class _MihCardsState extends State { return BuildLoyaltyCardList( cardList: searchShopName.value, signedInUser: widget.signedInUser, - navIndex: 1, + navIndex: 0, ); }, ); diff --git a/backend/routers/mzansi_wallet.py b/backend/routers/mzansi_wallet.py index 64551efe..37888447 100644 --- a/backend/routers/mzansi_wallet.py +++ b/backend/routers/mzansi_wallet.py @@ -19,11 +19,14 @@ class MzansiWalletInsertRequest(BaseModel): card_number: str favourite: str priority_index: int + nickname: str class MzansiWalletUpdateRequest(BaseModel): idloyalty_cards: int favourite: str priority_index: int + nickname: str + card_number: str # class patientNoteUpdateRequest(BaseModel): # idpatient_notes: int # note_name: str @@ -47,6 +50,7 @@ async def read_all_loyalty_cards_by_app_id(app_id: str, session: SessionContaine "card_number": item[3], "favourite": item[4], "priority_index": item[5], + "nickname": item[6], } for item in cursor.fetchall() ] @@ -69,6 +73,7 @@ async def read_favourite_loyalty_cards_by_app_id(app_id: str, session: SessionCo "card_number": item[3], "favourite": item[4], "priority_index": item[5], + "nickname": item[6], } for item in cursor.fetchall() ] @@ -106,13 +111,14 @@ async def insert_loyalty_card(itemRequest : MzansiWalletInsertRequest): #, sessi db = database.dbConnection.dbMzansiWalletConnect() cursor = db.cursor() query = "insert into loyalty_cards " - query += "(app_id, shop_name, card_number, favourite, priority_index) " - query += "values (%s, %s, %s, %s, %s)" + query += "(app_id, shop_name, card_number, favourite, priority_index, nickname) " + query += "values (%s, %s, %s, %s, %s, %s)" notetData = (itemRequest.app_id, itemRequest.shop_name, itemRequest.card_number, itemRequest.favourite, itemRequest.priority_index, + itemRequest.nickname, ) try: cursor.execute(query, notetData) @@ -152,10 +158,12 @@ async def UpdatePatient(itemRequest : MzansiWalletUpdateRequest, session: Sessio db = database.dbConnection.dbMzansiWalletConnect() cursor = db.cursor() query = "update loyalty_cards " - query += "set favourite=%s, priority_index=%s " + query += "set favourite=%s, priority_index=%s, nickname=%s, card_number=%s " query += "where idloyalty_cards=%s" notetData = (itemRequest.favourite, itemRequest.priority_index, + itemRequest.nickname, + itemRequest.card_number, itemRequest.idloyalty_cards, ) try: