From 2309af73a188223dac7f5b193ec2c2af060a1791 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 21 Jul 2025 11:32:50 +0200 Subject: [PATCH] new review window widget --- .../mih_review_business_window.dart | 424 ++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100644 Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart diff --git a/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart new file mode 100644 index 00000000..efaeb9a7 --- /dev/null +++ b/Frontend/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart @@ -0,0 +1,424 @@ +import 'package:custom_rating_bar/custom_rating_bar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_objects/business_review.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_text_form_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; +import 'package:supertokens_flutter/supertokens.dart'; + +class MihReviewBusinessWindow extends StatefulWidget { + final String businessId; + final BusinessReview? businessReview; + final double screenWidth; + const MihReviewBusinessWindow({ + super.key, + required this.businessId, + required this.businessReview, + required this.screenWidth, + }); + + @override + State createState() => + _MihReviewBusinessWindowState(); +} + +class _MihReviewBusinessWindowState extends State { + final _formKey = GlobalKey(); + final TextEditingController _reviewTitleController = TextEditingController(); + final TextEditingController _reviewScoreController = TextEditingController(); + final TextEditingController _reviewDescriptionController = + TextEditingController(); + late final VoidCallback _reviewDescriptionListener; + final ValueNotifier _counter = ValueNotifier(0); + String userId = ""; + + void showDeleteReviewAlert() { + showDialog( + context: context, + builder: (context) => MihPackageAlert( + alertColour: MzansiInnovationHub.of(context)!.theme.errorColor(), + alertIcon: Icon( + Icons.warning_rounded, + size: 100, + color: MzansiInnovationHub.of(context)!.theme.errorColor(), + ), + alertTitle: "Delete Review", + alertBody: Column( + children: [ + Text( + "Are you sure you want to delete this review? This action cannot be undone.", + style: TextStyle( + color: MzansiInnovationHub.of(context)!.theme.secondaryColor(), + fontSize: 15, + ), + ), + const SizedBox(height: 25), + Wrap( + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + width: 300, + onPressed: () async { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle(); + }, + ); + await MihMzansiDirectoryServices() + .deleteBusinessReview( + widget.businessReview!.idbusiness_ratings, + ) + .then((statusCode) { + Navigator.of(context).pop(); //Remove loading dialog + Navigator.of(context).pop(); //Remove delete dialog + if (statusCode == 200) { + Navigator.of(context).pop(); + MihAlertServices().successAlert( + "Successfully Deleted Review!", + "Your review has successfully been delete and will no longer appear under the business.", + context, + ); + } else { + MihAlertServices().errorAlert( + "Error Deleting Review", + "There was an error deleting your review. Please try again later.", + context, + ); + } + }); + }, + buttonColor: + MzansiInnovationHub.of(context)!.theme.errorColor(), + child: Text( + "Delete", + style: TextStyle( + color: + MzansiInnovationHub.of(context)!.theme.primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + MihButton( + width: 300, + onPressed: () { + Navigator.of(context).pop(); + }, + buttonColor: + MzansiInnovationHub.of(context)!.theme.successColor(), + child: Text( + "Cancel", + style: TextStyle( + color: + MzansiInnovationHub.of(context)!.theme.primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ], + ), + ), + ); + } + + Color getMissionVisionLimitColor(int limit) { + if (_counter.value <= limit) { + return MzansiInnovationHub.of(context)!.theme.secondaryColor(); + } else { + return MzansiInnovationHub.of(context)!.theme.errorColor(); + } + } + + void submitForm() async { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle(); + }, + ); + if (widget.businessReview != null) { + await MihMzansiDirectoryServices() + .updateBusinessReview( + widget.businessReview!.idbusiness_ratings, + _reviewTitleController.text, + _reviewDescriptionController.text, + _reviewScoreController.text, + ) + .then((statusCode) { + Navigator.of(context).pop(); //Remove loading dialog + if (statusCode == 200) { + Navigator.of(context).pop(); + MihAlertServices().successAlert( + "Successfully Updated Review!", + "Your review has successfully been updated and will now appear under the business.", + context, + ); + } else { + MihAlertServices().errorAlert( + "Error Updating Review", + "There was an error updating your review. Please try again later.", + context, + ); + } + }); + } else { + await MihMzansiDirectoryServices() + .addBusinessReview( + userId, + widget.businessId, + _reviewTitleController.text, + _reviewDescriptionController.text, + _reviewScoreController.text, + ) + .then((statusCode) { + Navigator.of(context).pop(); //Remove loading dialog + if (statusCode == 201) { + Navigator.of(context).pop(); + MihAlertServices().successAlert( + "Successfully Added Review!", + "Your review has successfully been added and will now appear under the business.", + context, + ); + } else { + MihAlertServices().errorAlert( + "Error Adding Review", + "There was an error adding your review. Please try again later.", + context, + ); + } + }); + } + } + + @override + void dispose() { + super.dispose(); + _reviewDescriptionController.removeListener(_reviewDescriptionListener); + } + + @override + void initState() { + super.initState(); + _reviewDescriptionListener = () { + setState(() { + _counter.value = _reviewDescriptionController.text.characters.length; + }); + }; + _reviewDescriptionController.addListener(_reviewDescriptionListener); + if (widget.businessReview != null) { + setState(() { + _reviewTitleController.text = widget.businessReview!.rating_title; + _reviewDescriptionController.text = + widget.businessReview!.rating_description; + _reviewScoreController.text = widget.businessReview!.rating_score; + }); + } + SuperTokens.getUserId().then((value) { + setState(() { + userId = value; + }); + }); + } + + @override + Widget build(BuildContext context) { + // return const Placeholder(); + return MihPackageWindow( + fullscreen: false, + windowTitle: widget.businessReview != null ? "Edit Review" : "Add Review", + onWindowTapClose: () { + Navigator.of(context).pop(); + }, + menuOptions: widget.businessReview != null + ? [ + SpeedDialChild( + child: Icon( + Icons.delete, + color: MzansiInnovationHub.of(context)!.theme.primaryColor(), + ), + label: "Delete Review", + labelBackgroundColor: + MzansiInnovationHub.of(context)!.theme.successColor(), + labelStyle: TextStyle( + color: MzansiInnovationHub.of(context)!.theme.primaryColor(), + fontWeight: FontWeight.bold, + ), + backgroundColor: + MzansiInnovationHub.of(context)!.theme.successColor(), + onTap: () { + showDeleteReviewAlert(); + }, + ), + ] + : null, + windowBody: MihSingleChildScroll( + child: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: widget.screenWidth * 0.05) + : EdgeInsets.symmetric(horizontal: widget.screenWidth * 0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Business Rating", + textAlign: TextAlign.left, + style: TextStyle( + color: MzansiInnovationHub.of(context)! + .theme + .secondaryColor(), + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 4), + RatingBar( + size: 50, + alignment: Alignment.centerLeft, + filledIcon: Icons.star, + emptyIcon: Icons.star_border, + halfFilledIcon: Icons.star_half, + filledColor: + MzansiInnovationHub.of(context)!.theme.secondaryColor(), + emptyColor: + MzansiInnovationHub.of(context)!.theme.secondaryColor(), + halfFilledColor: + MzansiInnovationHub.of(context)!.theme.secondaryColor(), + isHalfAllowed: true, + initialRating: widget.businessReview != null + ? double.parse(_reviewScoreController.text) + : 1, + maxRating: 5, + onRatingChanged: (double) { + setState(() { + _reviewScoreController.text = double.toStringAsFixed(1); + }); + print(_reviewScoreController.text); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + // width: 200, + fillColor: + MzansiInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzansiInnovationHub.of(context)!.theme.primaryColor(), + controller: _reviewTitleController, + multiLineInput: false, + requiredText: true, + hintText: "Review Title", + validator: (value) { + return MihValidationServices() + .isEmpty(_reviewTitleController.text); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + height: 250, + fillColor: + MzansiInnovationHub.of(context)!.theme.secondaryColor(), + inputColor: + MzansiInnovationHub.of(context)!.theme.primaryColor(), + controller: _reviewDescriptionController, + multiLineInput: true, + requiredText: false, + hintText: "Review Description", + validator: (value) { + if (_reviewDescriptionController.text.isEmpty) { + return null; + } else { + return MihValidationServices().validateLength( + _reviewDescriptionController.text, 256); + } + }, + ), + SizedBox( + height: 15, + child: ValueListenableBuilder( + valueListenable: _counter, + builder: + (BuildContext context, int value, Widget? child) { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "$value", + style: TextStyle( + color: getMissionVisionLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 5), + Text( + "/256", + style: TextStyle( + color: getMissionVisionLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + ], + ); + }, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(); + } else { + MihAlertServices().formNotFilledCompletely(context); + } + }, + buttonColor: + MzansiInnovationHub.of(context)!.theme.successColor(), + width: 300, + child: Text( + widget.businessReview != null + ? "Edit Review" + : "Add Review", + style: TextStyle( + color: MzansiInnovationHub.of(context)! + .theme + .primaryColor(), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ); + } +}