From 743b6516dcbd988cfd378cfeaf25f2331da3ef86 Mon Sep 17 00:00:00 2001 From: Daniela Damaschin Date: Tue, 5 Nov 2024 17:03:33 +0100 Subject: [PATCH 1/5] Move to new giving cubit and endpoint for US adults (kids-1499) --- lib/app/routes/app_router.dart | 18 +-- lib/features/family/app/injection.dart | 8 +- .../models/transaction.dart | 3 + .../screens/choose_amount_slider_screen.dart | 4 +- .../parent_giving_flow/cubit/give_cubit.dart | 40 +++++++ .../parent_giving_flow/cubit/give_state.dart | 51 ++++++++ .../pages/give_from_list_page.dart | 40 +++---- .../pages/parent_amount_page.dart | 6 +- .../pages/parent_giving_page.dart | 37 ++---- .../presentation/pages/grateful_screen.dart | 35 +++--- .../give/models/givt_transaction.dart | 12 ++ .../pages/impact_group_details_page.dart | 108 ----------------- .../impact_group_details_bottom_panel.dart | 75 ------------ ..._group_details_expandable_description.dart | 83 ------------- .../widgets/impact_group_details_header.dart | 110 ------------------ 15 files changed, 158 insertions(+), 472 deletions(-) create mode 100644 lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart create mode 100644 lib/features/family/features/parent_giving_flow/cubit/give_state.dart delete mode 100644 lib/features/impact_groups/pages/impact_group_details_page.dart delete mode 100644 lib/features/impact_groups/widgets/impact_group_details_bottom_panel.dart delete mode 100644 lib/features/impact_groups/widgets/impact_group_details_expandable_description.dart delete mode 100644 lib/features/impact_groups/widgets/impact_group_details_header.dart diff --git a/lib/app/routes/app_router.dart b/lib/app/routes/app_router.dart index 23d1154af..d2e91b2a9 100644 --- a/lib/app/routes/app_router.dart +++ b/lib/app/routes/app_router.dart @@ -22,8 +22,6 @@ import 'package:givt_app/features/give/pages/organization_list_page.dart'; import 'package:givt_app/features/give/pages/qr_code_scan_page.dart'; import 'package:givt_app/features/give/pages/select_giving_way_page.dart'; import 'package:givt_app/features/give/pages/success_donation_page.dart'; -import 'package:givt_app/features/impact_groups/models/impact_group.dart'; -import 'package:givt_app/features/impact_groups/pages/impact_group_details_page.dart'; import 'package:givt_app/features/overview/bloc/givt_bloc.dart'; import 'package:givt_app/features/overview/pages/overview_page.dart'; import 'package:givt_app/features/permit_biometric/cubit/permit_biometric_cubit.dart'; @@ -142,21 +140,7 @@ class AppRouter { child: const LoadingPage(), ), ), - GoRoute( - path: Pages.impactGroupDetails.path, - name: Pages.impactGroupDetails.name, - builder: (context, state) => BlocProvider( - create: (_) => GiveBloc( - getIt(), - getIt(), - getIt(), - getIt(), - ), - child: ImpactGroupDetailsPage( - impactGroup: state.extra! as ImpactGroup, - ), - ), - ), + GoRoute( path: Pages.home.path, name: Pages.home.name, diff --git a/lib/features/family/app/injection.dart b/lib/features/family/app/injection.dart index 5f4ec9e90..3abd559ac 100644 --- a/lib/features/family/app/injection.dart +++ b/lib/features/family/app/injection.dart @@ -12,6 +12,7 @@ import 'package:givt_app/features/family/features/history/history_repository/his import 'package:givt_app/features/family/features/home_screen/cubit/family_home_screen_cubit.dart'; import 'package:givt_app/features/family/features/home_screen/cubit/navigation_bar_home_cubit.dart'; import 'package:givt_app/features/family/features/impact_groups/repository/impact_groups_repository.dart'; +import 'package:givt_app/features/family/features/parent_giving_flow/cubit/give_cubit.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/cubit/medium_cubit.dart'; import 'package:givt_app/features/family/features/profiles/repository/profiles_repository.dart'; import 'package:givt_app/features/family/features/qr_scanner/cubit/camera_cubit.dart'; @@ -66,11 +67,8 @@ void initCubits() { CameraCubit.new, ) ..registerLazySingleton(MediumCubit.new) - ..registerLazySingleton( - () => GiveBloc( - getIt(), - getIt(), - getIt(), + ..registerLazySingleton( + () => GiveCubit( getIt(), ), ) diff --git a/lib/features/family/features/giving_flow/create_transaction/models/transaction.dart b/lib/features/family/features/giving_flow/create_transaction/models/transaction.dart index 47673c325..f4ac12cb8 100644 --- a/lib/features/family/features/giving_flow/create_transaction/models/transaction.dart +++ b/lib/features/family/features/giving_flow/create_transaction/models/transaction.dart @@ -4,12 +4,14 @@ class Transaction { required this.mediumId, required this.amount, this.goalId, + this.isActOfService = false, }); final String userId; final String mediumId; final double amount; final String? goalId; + final bool isActOfService; Map toJson() { return { @@ -17,6 +19,7 @@ class Transaction { 'mediumId': mediumId, 'amount': amount, 'goalId': goalId, + 'isActOfService': isActOfService, }; } } diff --git a/lib/features/family/features/giving_flow/screens/choose_amount_slider_screen.dart b/lib/features/family/features/giving_flow/screens/choose_amount_slider_screen.dart index 342a7169d..1f0efa030 100644 --- a/lib/features/family/features/giving_flow/screens/choose_amount_slider_screen.dart +++ b/lib/features/family/features/giving_flow/screens/choose_amount_slider_screen.dart @@ -30,10 +30,11 @@ class ChooseAmountSliderScreen extends StatelessWidget { const ChooseAmountSliderScreen({ super.key, this.onCustomSuccess, + this.isActOfService = false, }); final void Function()? onCustomSuccess; - + final bool isActOfService; @override Widget build(BuildContext context) { final flow = context.read().state; @@ -106,6 +107,7 @@ class ChooseAmountSliderScreen extends StatelessWidget { userId: profilesCubit.state.activeProfile.id, mediumId: mediumId, amount: state.amount, + isActOfService: isActOfService, ); await context diff --git a/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart b/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart new file mode 100644 index 000000000..938e4bcaa --- /dev/null +++ b/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart @@ -0,0 +1,40 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:givt_app/core/logging/logging_service.dart'; +import 'package:givt_app/features/family/features/giving_flow/create_transaction/models/transaction.dart'; +import 'package:givt_app/features/family/features/giving_flow/create_transaction/repositories/create_transaction_repository.dart'; +import 'package:givt_app/features/give/models/givt_transaction.dart'; +import 'package:givt_app/shared/models/collect_group.dart'; + +part 'give_state.dart'; + +class GiveCubit extends Cubit { + GiveCubit( + this._createTransactionRepository, + ) : super(GiveInitial()); + final CreateTransactionRepository _createTransactionRepository; + + Future createTransaction( + {required Transaction transaction, + required String orgName, + required String mediumId}) async { + emit(GiveLoading()); + try { + await _createTransactionRepository.createTransaction( + transaction: transaction, + ); + emit(GiveFromBrowser(GivtTransaction.fromTransaction(transaction), + transaction, orgName, mediumId)); + } catch (error, stackTrace) { + LoggingInfo.instance.error( + 'Error while creating transaction: $error', + methodName: stackTrace.toString(), + ); + emit(const GiveError('Error creating transaction.')); + } + } + + void reset() { + emit(GiveInitial()); + } +} diff --git a/lib/features/family/features/parent_giving_flow/cubit/give_state.dart b/lib/features/family/features/parent_giving_flow/cubit/give_state.dart new file mode 100644 index 000000000..b2780f5d6 --- /dev/null +++ b/lib/features/family/features/parent_giving_flow/cubit/give_state.dart @@ -0,0 +1,51 @@ +part of 'give_cubit.dart'; + +sealed class GiveState extends Equatable { + const GiveState(); + + @override + List get props => []; +} + +final class GiveInitial extends GiveState {} + +final class GiveLoading extends GiveState {} + +final class GiveFromBrowser extends GiveState { + const GiveFromBrowser( + this.givtTransactionObject, + this.transaction, + this.orgName, + this.mediumId, + ); + +// this is legacy for the browser page + final GivtTransaction givtTransactionObject; + // this is the object we use for parent giving in US + final Transaction transaction; + final String orgName; + final String mediumId; + + @override + List get props => + [givtTransactionObject, transaction, orgName, mediumId]; +} + +final class GiveSuccess extends GiveState { + const GiveSuccess(this.amount, this.isActOfService); + + final double amount; + final bool isActOfService; + + @override + List get props => [amount, isActOfService]; +} + +final class GiveError extends GiveState { + const GiveError(this.error); + + final String error; + + @override + List get props => [error]; +} diff --git a/lib/features/family/features/parent_giving_flow/presentation/pages/give_from_list_page.dart b/lib/features/family/features/parent_giving_flow/presentation/pages/give_from_list_page.dart index 012d6a0e5..e94480f39 100644 --- a/lib/features/family/features/parent_giving_flow/presentation/pages/give_from_list_page.dart +++ b/lib/features/family/features/parent_giving_flow/presentation/pages/give_from_list_page.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -8,11 +9,12 @@ import 'package:givt_app/core/enums/collect_group_type.dart'; import 'package:givt_app/features/auth/cubit/auth_cubit.dart'; import 'package:givt_app/features/family/app/family_pages.dart'; import 'package:givt_app/features/family/extensions/extensions.dart'; +import 'package:givt_app/features/family/features/giving_flow/create_transaction/models/transaction.dart'; +import 'package:givt_app/features/family/features/parent_giving_flow/cubit/give_cubit.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/cubit/medium_cubit.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/presentation/pages/organisation_list_family_page.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/presentation/pages/parent_amount_page.dart'; import 'package:givt_app/features/family/shared/widgets/loading/custom_progress_indicator.dart'; -import 'package:givt_app/features/give/bloc/give/give_bloc.dart'; import 'package:givt_app/l10n/l10n.dart'; import 'package:givt_app/shared/models/collect_group.dart'; import 'package:givt_app/utils/analytics_helper.dart'; @@ -24,25 +26,16 @@ class GiveFromListPage extends StatelessWidget { @override Widget build(BuildContext context) { final locals = context.l10n; - final give = getIt(); - return BlocConsumer( + final give = getIt(); + return BlocConsumer( bloc: give, listener: (context, state) { - final userGUID = context.read().state.user.guid; - if (state.status == GiveStatus.success) { - give.add( - GiveOrganisationSelected( - nameSpace: getIt().state.mediumId, - userGUID: userGUID, - ), - ); - } - if (state.status == GiveStatus.readyToGive) { + if (state is GiveFromBrowser) { context.pushReplacementNamed( FamilyPages.parentGive.name, ); } - if (state.status == GiveStatus.error) { + if (state is GiveError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(locals.somethingWentWrong), @@ -50,9 +43,7 @@ class GiveFromListPage extends StatelessWidget { ); } }, - builder: (context, giveState) => giveState.status == GiveStatus.loading || - giveState.status == GiveStatus.processed || - giveState.status == GiveStatus.success + builder: (context, giveState) => giveState is GiveLoading ? const Scaffold(body: CustomCircularProgressIndicator()) : OrganisationListFamilyPage( onTap: (CollectGroup collectGroup) { @@ -95,13 +86,14 @@ class GiveFromListPage extends StatelessWidget { }, ), ); - getIt().add( - GiveAmountChanged( - firstCollectionAmount: result.toDouble(), - secondCollectionAmount: 0, - thirdCollectionAmount: 0, - ), - ); + await getIt().createTransaction( + transaction: Transaction( + userId: context.read().state.user.guid, + mediumId: base64Encode(utf8.encode(collectGroup.nameSpace)), + amount: result.toDouble(), + ), + orgName: collectGroup.orgName, + mediumId: collectGroup.nameSpace); } } } diff --git a/lib/features/family/features/parent_giving_flow/presentation/pages/parent_amount_page.dart b/lib/features/family/features/parent_giving_flow/presentation/pages/parent_amount_page.dart index a6daea701..8239b3d9c 100644 --- a/lib/features/family/features/parent_giving_flow/presentation/pages/parent_amount_page.dart +++ b/lib/features/family/features/parent_giving_flow/presentation/pages/parent_amount_page.dart @@ -2,13 +2,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:givt_app/core/enums/amplitude_events.dart'; import 'package:givt_app/features/auth/cubit/auth_cubit.dart'; -import 'package:givt_app/features/family/shared/widgets/buttons/givt_back_button_flat.dart'; -import 'package:givt_app/features/registration/pages/credit_card_details.dart'; -import 'package:givt_app/shared/models/color_combo.dart'; import 'package:givt_app/features/family/shared/design/components/components.dart'; +import 'package:givt_app/features/family/shared/widgets/buttons/givt_back_button_flat.dart'; import 'package:givt_app/features/family/shared/widgets/texts/shared_texts.dart'; import 'package:givt_app/features/family/utils/family_auth_utils.dart'; +import 'package:givt_app/features/registration/pages/credit_card_details.dart'; import 'package:givt_app/shared/models/analytics_event.dart'; +import 'package:givt_app/shared/models/color_combo.dart'; import 'package:givt_app/shared/widgets/common_icons.dart'; class ParentAmountPage extends StatefulWidget { diff --git a/lib/features/family/features/parent_giving_flow/presentation/pages/parent_giving_page.dart b/lib/features/family/features/parent_giving_flow/presentation/pages/parent_giving_page.dart index 9c904b219..37d4e8e34 100644 --- a/lib/features/family/features/parent_giving_flow/presentation/pages/parent_giving_page.dart +++ b/lib/features/family/features/parent_giving_flow/presentation/pages/parent_giving_page.dart @@ -8,13 +8,11 @@ import 'package:givt_app/app/injection/injection.dart'; import 'package:givt_app/core/logging/logging.dart'; import 'package:givt_app/core/network/request_helper.dart'; import 'package:givt_app/features/auth/cubit/auth_cubit.dart'; -import 'package:givt_app/features/give/bloc/bloc.dart'; +import 'package:givt_app/features/family/features/parent_giving_flow/cubit/give_cubit.dart'; import 'package:givt_app/features/give/models/models.dart'; import 'package:givt_app/features/impact_groups/cubit/impact_groups_cubit.dart'; import 'package:givt_app/l10n/l10n.dart'; import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; -import 'package:url_launcher/url_launcher.dart'; import 'package:vibration/vibration.dart'; class ParentGivingPage extends StatefulWidget { @@ -29,7 +27,7 @@ class _ParentGivingPageState extends State { late CustomInAppBrowser _customInAppBrowser; bool browserIsOpened = false; bool browserClosing = false; - final give = getIt(); + final give = getIt(); @override void initState() { @@ -65,25 +63,13 @@ class _ParentGivingPageState extends State { return; } - give.add(const GiveReset()); + give.reset(); unawaited( context.read().fetchImpactGroups(), ); - final afterGivingRedirection = give.state.afterGivingRedirection; context.pop(true); - - if (afterGivingRedirection.isNotEmpty) { - final url = Uri.parse(afterGivingRedirection); - LoggingInfo.instance.info( - 'Redirecting after external link donation. Attempting to launch $url', - ); - if (!await launchUrl(url)) { - LoggingInfo.instance.error('Could not launch $url'); - throw Exception('Could not launch $url'); - } - } } catch (e) { setState(() { browserClosing = false; @@ -95,26 +81,21 @@ class _ParentGivingPageState extends State { BuildContext context, ) { final user = context.read().state.user; - final format = NumberFormat.simpleCurrency( - name: give.state.organisation.currency, - ); - var orgName = give.state.organisation.organisationName!; - final instanceName = give.state.instanceName; - if (give.state.instanceName.isNotEmpty && instanceName != orgName) { - orgName = '$orgName: $instanceName'; - } + final state = give.state as GiveFromBrowser; + + final orgName = state.orgName; return WebViewInput( - currency: format.currencySymbol, + currency: r'$', apiUrl: Uri.https(getIt().apiURL).toString(), guid: user.guid, organisation: orgName, - givtObj: GivtTransaction.toJsonList(give.state.givtTransactions), + givtObj: GivtTransaction.toJsonList([state.givtTransactionObject]), confirmBtn: context.l10n.next, cancel: context.l10n.cancel, areYouSureToCancelGivts: context.l10n.areYouSureToCancelGivts, message: context.l10n.safariGivtTransaction, thanks: context.l10n.givtIsBeingProcessed( - give.state.organisation.organisationName.toString(), + orgName, ), yesSuccess: context.l10n.yesSuccess, close: context.l10n.close, diff --git a/lib/features/family/features/reflect/presentation/pages/grateful_screen.dart b/lib/features/family/features/reflect/presentation/pages/grateful_screen.dart index 0f510b978..adb93f1ce 100644 --- a/lib/features/family/features/reflect/presentation/pages/grateful_screen.dart +++ b/lib/features/family/features/reflect/presentation/pages/grateful_screen.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -8,8 +9,10 @@ import 'package:givt_app/features/auth/cubit/auth_cubit.dart'; import 'package:givt_app/features/family/app/injection.dart'; import 'package:givt_app/features/family/extensions/extensions.dart'; import 'package:givt_app/features/family/features/giving_flow/create_transaction/cubit/create_transaction_cubit.dart'; +import 'package:givt_app/features/family/features/giving_flow/create_transaction/models/transaction.dart'; import 'package:givt_app/features/family/features/giving_flow/screens/choose_amount_slider_screen.dart'; import 'package:givt_app/features/family/features/giving_flow/screens/success_screen.dart'; +import 'package:givt_app/features/family/features/parent_giving_flow/cubit/give_cubit.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/cubit/medium_cubit.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/presentation/pages/parent_amount_page.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/presentation/pages/parent_giving_page.dart'; @@ -28,7 +31,6 @@ import 'package:givt_app/features/family/features/topup/screens/empty_wallet_bot import 'package:givt_app/features/family/shared/design/components/components.dart'; import 'package:givt_app/features/family/shared/widgets/loading/full_screen_loading_widget.dart'; import 'package:givt_app/features/family/utils/family_app_theme.dart'; -import 'package:givt_app/features/give/bloc/give/give_bloc.dart'; import 'package:givt_app/l10n/l10n.dart'; import 'package:givt_app/shared/widgets/base/base_state_consumer.dart'; import 'package:givt_app/shared/widgets/fun_scaffold.dart'; @@ -44,7 +46,7 @@ class GratefulScreen extends StatefulWidget { class _GratefulScreenState extends State { final _cubit = getIt(); - final _give = getIt(); + final _give = getIt(); final _medium = getIt(); @override @@ -61,23 +63,15 @@ class _GratefulScreenState extends State { @override Widget build(BuildContext context) { - return BlocListener( + return BlocListener( bloc: _give, listener: (context, state) { final userGUID = context.read().state.user.guid; - if (state.status == GiveStatus.success) { - _give.add( - GiveOrganisationSelected( - nameSpace: _medium.state.mediumId, - userGUID: userGUID, - ), - ); - } - if (state.status == GiveStatus.readyToGive) { + if (state is GiveFromBrowser) { // we assume the parent confirms on browser _handleParentBrowser(userGUID); } - if (state.status == GiveStatus.error) { + if (state is GiveError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(context.l10n.somethingWentWrong), @@ -180,6 +174,7 @@ class _GratefulScreenState extends State { _cubit.onDeed(profile); context.pop(); }, + isActOfService: true, ), ).toRoute(context), ); @@ -238,13 +233,17 @@ class _GratefulScreenState extends State { }, ), ); - _give.add( - GiveAmountChanged( - firstCollectionAmount: result.toDouble(), - secondCollectionAmount: 0, - thirdCollectionAmount: 0, + await _give.createTransaction( + transaction: Transaction( + userId: context.read().state.user.guid, + mediumId: base64Encode(utf8.encode(org.namespace)), + amount: result.toDouble(), + isActOfService: true, ), + orgName: org.name, + mediumId: org.namespace, ); + await Navigator.push( context, const FullScreenLoadingWidget( diff --git a/lib/features/give/models/givt_transaction.dart b/lib/features/give/models/givt_transaction.dart index a82eb61c9..86dcf2028 100644 --- a/lib/features/give/models/givt_transaction.dart +++ b/lib/features/give/models/givt_transaction.dart @@ -1,6 +1,18 @@ import 'package:equatable/equatable.dart'; +import 'package:givt_app/features/family/features/giving_flow/create_transaction/models/transaction.dart'; +import 'package:intl/intl.dart'; class GivtTransaction extends Equatable { + GivtTransaction.fromTransaction(Transaction transaction) + : guid = transaction.userId, + amount = transaction.amount, + beaconId = transaction.mediumId, + timestamp = DateFormat('yyyy-MM-ddTHH:mm:ss').format( + DateTime.now().toUtc(), + ), + collectId = '1', + goalId = transaction.goalId, + mediumId = transaction.mediumId; const GivtTransaction({ required this.guid, required this.amount, diff --git a/lib/features/impact_groups/pages/impact_group_details_page.dart b/lib/features/impact_groups/pages/impact_group_details_page.dart deleted file mode 100644 index b6583ff9a..000000000 --- a/lib/features/impact_groups/pages/impact_group_details_page.dart +++ /dev/null @@ -1,108 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:givt_app/app/routes/pages.dart'; -import 'package:givt_app/features/give/bloc/give/give_bloc.dart'; -import 'package:givt_app/features/impact_groups/models/impact_group.dart'; -import 'package:givt_app/features/impact_groups/widgets/impact_group_details_bottom_panel.dart'; -import 'package:givt_app/features/impact_groups/widgets/impact_group_details_expandable_description.dart'; -import 'package:givt_app/features/impact_groups/widgets/impact_group_details_header.dart'; -import 'package:givt_app/l10n/l10n.dart'; -import 'package:givt_app/shared/dialogs/warning_dialog.dart'; -import 'package:go_router/go_router.dart'; - -class ImpactGroupDetailsPage extends StatelessWidget { - const ImpactGroupDetailsPage({ - required this.impactGroup, - super.key, - }); - - final ImpactGroup impactGroup; - - @override - Widget build(BuildContext context) { - final bottomPadding = MediaQuery.of(context).padding.bottom; - - //PP: this is a temp, ugly solution - final bottomPanelHeight = 231 + bottomPadding; - - return BlocListener( - listener: (context, state) { - if (state.status == GiveStatus.noInternetConnection) { - context.goNamed( - Pages.giveSucess.name, - extra: { - 'isRecurringDonation': false, - 'orgName': state.organisation.organisationName, - }, - ); - } - if (state.status == GiveStatus.error) { - showDialog( - context: context, - builder: (_) => WarningDialog( - title: context.l10n.errorOccurred, - content: context.l10n.errorContactGivt, - onConfirm: () => context.pop(), - ), - ); - } - if (state.status == - GiveStatus.donatedToSameOrganisationInLessThan30Seconds) { - showDialog( - context: context, - builder: (_) => WarningDialog( - title: context.l10n.notSoFast, - content: context.l10n.giftBetween30Sec, - onConfirm: () => context.pop(), - ), - ); - } - }, - child: Scaffold( - appBar: AppBar( - leading: const BackButton(), - title: Text( - impactGroup.isFamilyGroup - ? context.l10n.familyGroup - : impactGroup.name, - ), - ), - body: CustomScrollView( - slivers: [ - SliverToBoxAdapter( - child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ImpactGroupDetailsHeader(impactGroup: impactGroup), - Padding( - padding: const EdgeInsets.only(top: 10, right: 20), - child: ImpactGroupDetailsExpandableDescription( - description: impactGroup.description, - ), - ), - ], - ), - ), - ), - SliverFillRemaining( - hasScrollBody: false, - fillOverscroll: true, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Flexible(child: SizedBox.expand()), - SizedBox( - height: bottomPanelHeight, - child: - ImpactGroupDetailsBottomPanel(impactGroup: impactGroup), - ), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/features/impact_groups/widgets/impact_group_details_bottom_panel.dart b/lib/features/impact_groups/widgets/impact_group_details_bottom_panel.dart deleted file mode 100644 index c4dead35b..000000000 --- a/lib/features/impact_groups/widgets/impact_group_details_bottom_panel.dart +++ /dev/null @@ -1,75 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:givt_app/core/enums/enums.dart'; -import 'package:givt_app/features/give/bloc/give/give_bloc.dart'; -import 'package:givt_app/features/give/widgets/enter_amount_bottom_sheet.dart'; -import 'package:givt_app/features/impact_groups/models/impact_group.dart'; -import 'package:givt_app/l10n/l10n.dart'; -import 'package:givt_app/shared/widgets/buttons/custom_green_elevated_button.dart'; -import 'package:givt_app/shared/widgets/goal_progress_bar/goal_progress_bar.dart'; -import 'package:givt_app/utils/utils.dart'; -import 'package:google_fonts/google_fonts.dart'; - -class ImpactGroupDetailsBottomPanel extends StatelessWidget { - const ImpactGroupDetailsBottomPanel({ - required this.impactGroup, - super.key, - }); - - final ImpactGroup impactGroup; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.only(left: 24, right: 24, top: 10, bottom: 16), - color: AppTheme.generosityChallangeCardBackground, - child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - '${context.l10n.goal}${impactGroup.isFamilyGroup ? ': ${impactGroup.organisation.organisationName}' : ''}', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: GoogleFonts.mulish( - textStyle: Theme.of(context).textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.w800, - ), - ), - ), - const SizedBox(height: 5), - GoalProgressBar( - goal: impactGroup.goal, - showFlag: true, - showCurrentLabel: true, - showGoalLabel: true, - ), - const SizedBox(height: 15), - CustomElevatedButton( - title: context.l10n.give, - onPressed: () { - AnalyticsHelper.logEvent( - eventName: AmplitudeEvents.impactGroupDetailsGiveClicked, - eventProperties: {'name': impactGroup.name}, - ); - final giveBloc = context.read(); - showModalBottomSheet( - context: context, - isScrollControlled: true, - useSafeArea: true, - builder: (_) => BlocProvider.value( - value: giveBloc, - child: EnterAmountBottomSheet( - collectGroupNameSpace: impactGroup.goal.mediumId, - ), - ), - ); - }, - ), - ], - ), - ), - ); - } -} diff --git a/lib/features/impact_groups/widgets/impact_group_details_expandable_description.dart b/lib/features/impact_groups/widgets/impact_group_details_expandable_description.dart deleted file mode 100644 index 1a53af511..000000000 --- a/lib/features/impact_groups/widgets/impact_group_details_expandable_description.dart +++ /dev/null @@ -1,83 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:givt_app/core/enums/enums.dart'; -import 'package:givt_app/features/impact_groups/dialogs/impact_group_details_description_dialog.dart'; -import 'package:givt_app/l10n/l10n.dart'; -import 'package:givt_app/utils/utils.dart'; -import 'package:google_fonts/google_fonts.dart'; - -class ImpactGroupDetailsExpandableDescription extends StatelessWidget { - const ImpactGroupDetailsExpandableDescription({ - required this.description, - super.key, - }); - - final String description; - - int _calculateLinesNumber(String text, TextStyle style, double maxWidth) { - final textSpan = TextSpan(text: description, style: style); - final textPainter = - TextPainter(text: textSpan, textDirection: TextDirection.ltr) - ..layout(maxWidth: maxWidth); - return textPainter.computeLineMetrics().length; - } - - @override - Widget build(BuildContext context) { - final textStyle = GoogleFonts.mulish( - textStyle: Theme.of(context).textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w500, - ), - ); - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: LayoutBuilder( - builder: (context, constraints) { - final numLines = _calculateLinesNumber( - description, - textStyle, - constraints.maxWidth, - ); - - if (numLines > 2) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - description, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: textStyle, - ), - TextButton( - onPressed: () { - AnalyticsHelper.logEvent( - eventName: - AmplitudeEvents.impactGroupDetailsReadMoreClicked, - ); - - ImpactGroupDetailsDescriptionDialog - .showImpactGroupDescriptionDialog( - context: context, - description: description, - ); - }, - style: TextButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 2), - ), - child: Text( - context.l10n.featureReadMore, - style: textStyle.copyWith( - decoration: TextDecoration.underline, - ), - ), - ), - ], - ); - } else { - return Text(description, style: textStyle); - } - }, - ), - ); - } -} diff --git a/lib/features/impact_groups/widgets/impact_group_details_header.dart b/lib/features/impact_groups/widgets/impact_group_details_header.dart deleted file mode 100644 index a4deaf1de..000000000 --- a/lib/features/impact_groups/widgets/impact_group_details_header.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:givt_app/features/impact_groups/models/impact_group.dart'; -import 'package:givt_app/l10n/l10n.dart'; -import 'package:google_fonts/google_fonts.dart'; - -class ImpactGroupDetailsHeader extends StatelessWidget { - const ImpactGroupDetailsHeader({ - required this.impactGroup, - super.key, - }); - - final ImpactGroup impactGroup; - - Widget _createPicture({ - required String path, - double? width, - double? height, - bool isAsset = true, - }) { - return isAsset - ? SvgPicture.asset(path, width: width, height: height) - : SvgPicture.network(path, width: width, height: height); - } - - @override - Widget build(BuildContext context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (impactGroup.isFamilyGroup) - const SizedBox(height: 30) - else - Image.network(impactGroup.image), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: Row( - children: [ - Transform.translate( - offset: const Offset(0, -6), - child: _createPicture( - path: impactGroup.isFamilyGroup - ? 'assets/images/family_avatar.svg' - : impactGroup.organiser.avatar, - width: 70, - height: 70, - isAsset: impactGroup.isFamilyGroup, - ), - ), - const SizedBox(width: 8), - Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - impactGroup.isFamilyGroup - ? context.l10n.theFamilyWithName(impactGroup.name) - : impactGroup.organiser.fullName, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: GoogleFonts.mulish( - textStyle: Theme.of(context) - .textTheme - .titleLarge - ?.copyWith(fontWeight: FontWeight.w800), - ), - ), - Row( - children: [ - Text( - '${context.l10n.goal}: \$${impactGroup.goal.goalAmount}', - style: GoogleFonts.mulish( - textStyle: Theme.of(context) - .textTheme - .titleMedium - ?.copyWith(fontWeight: FontWeight.w500), - ), - ), - if (!impactGroup.isFamilyGroup) - Text( - ' ยท ', - style: GoogleFonts.mulish( - textStyle: Theme.of(context) - .textTheme - .titleMedium - ?.copyWith(fontWeight: FontWeight.w500), - ), - ), - if (!impactGroup.isFamilyGroup) - Text( - '${impactGroup.amountOfMembers} ${context.l10n.members}', - style: GoogleFonts.mulish( - textStyle: Theme.of(context) - .textTheme - .titleMedium - ?.copyWith(fontWeight: FontWeight.w500), - ), - ), - ], - ), - ], - ), - ), - ], - ), - ), - ], - ); - } -} From d5ba450c645c5090672eaa4253090cae3eee8832 Mon Sep 17 00:00:00 2001 From: Daniela Damaschin Date: Wed, 6 Nov 2024 10:51:41 +0100 Subject: [PATCH 2/5] add more analytics and error handling --- lib/core/enums/amplitude_events.dart | 1 + .../parent_giving_flow/cubit/give_cubit.dart | 12 +++++++++++- .../parent_giving_flow/cubit/give_state.dart | 10 ---------- .../presentation/pages/parent_giving_page.dart | 7 +++++++ 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/core/enums/amplitude_events.dart b/lib/core/enums/amplitude_events.dart index 3050af03b..645a9ef5b 100644 --- a/lib/core/enums/amplitude_events.dart +++ b/lib/core/enums/amplitude_events.dart @@ -255,6 +255,7 @@ enum AmplitudeEvents { parentGiveWithAmountClicked('parent_give_with_amount_clicked'), parentGiveClicked('parent_give_clicked'), parentGiveFilterTileClicked('parent_give_filter_tile_clicked'), + parentGaveSuccessfully('parent_gave_successfully'), // Reflect and Share reflectandShareAssignRolesClicked('reflect_and_share_assign_roles_clicked'), diff --git a/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart b/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart index 938e4bcaa..a20105c0e 100644 --- a/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart +++ b/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart @@ -1,10 +1,11 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:givt_app/core/enums/amplitude_events.dart'; import 'package:givt_app/core/logging/logging_service.dart'; import 'package:givt_app/features/family/features/giving_flow/create_transaction/models/transaction.dart'; import 'package:givt_app/features/family/features/giving_flow/create_transaction/repositories/create_transaction_repository.dart'; import 'package:givt_app/features/give/models/givt_transaction.dart'; -import 'package:givt_app/shared/models/collect_group.dart'; +import 'package:givt_app/utils/analytics_helper.dart'; part 'give_state.dart'; @@ -23,6 +24,15 @@ class GiveCubit extends Cubit { await _createTransactionRepository.createTransaction( transaction: transaction, ); + + await AnalyticsHelper.logEvent( + eventName: AmplitudeEvents.parentGaveSuccessfully, + eventProperties: { + 'amount': transaction.amount, + 'organisation': orgName, + 'mediumid': mediumId, + }, + ); emit(GiveFromBrowser(GivtTransaction.fromTransaction(transaction), transaction, orgName, mediumId)); } catch (error, stackTrace) { diff --git a/lib/features/family/features/parent_giving_flow/cubit/give_state.dart b/lib/features/family/features/parent_giving_flow/cubit/give_state.dart index b2780f5d6..070ec73e5 100644 --- a/lib/features/family/features/parent_giving_flow/cubit/give_state.dart +++ b/lib/features/family/features/parent_giving_flow/cubit/give_state.dart @@ -31,16 +31,6 @@ final class GiveFromBrowser extends GiveState { [givtTransactionObject, transaction, orgName, mediumId]; } -final class GiveSuccess extends GiveState { - const GiveSuccess(this.amount, this.isActOfService); - - final double amount; - final bool isActOfService; - - @override - List get props => [amount, isActOfService]; -} - final class GiveError extends GiveState { const GiveError(this.error); diff --git a/lib/features/family/features/parent_giving_flow/presentation/pages/parent_giving_page.dart b/lib/features/family/features/parent_giving_flow/presentation/pages/parent_giving_page.dart index 37d4e8e34..12a4c72e5 100644 --- a/lib/features/family/features/parent_giving_flow/presentation/pages/parent_giving_page.dart +++ b/lib/features/family/features/parent_giving_flow/presentation/pages/parent_giving_page.dart @@ -81,6 +81,13 @@ class _ParentGivingPageState extends State { BuildContext context, ) { final user = context.read().state.user; + if (give.state is! GiveFromBrowser) { + LoggingInfo.instance.error( + 'Invalid state type in parent giving flow. Expected GiveFromBrowser, got ${give.state.runtimeType}', + ); + throw StateError('Invalid giving state'); + } + final state = give.state as GiveFromBrowser; final orgName = state.orgName; From 0953b5cb705d1e29f9dc37e2c28efcfd944652d9 Mon Sep 17 00:00:00 2001 From: Daniela Damaschin Date: Wed, 6 Nov 2024 10:53:45 +0100 Subject: [PATCH 3/5] remove more unused code --- lib/app/routes/pages.dart | 5 ----- lib/core/enums/amplitude_events.dart | 2 -- lib/features/family/app/family_pages.dart | 4 ---- 3 files changed, 11 deletions(-) diff --git a/lib/app/routes/pages.dart b/lib/app/routes/pages.dart index 5f5a053ef..c16de7c57 100644 --- a/lib/app/routes/pages.dart +++ b/lib/app/routes/pages.dart @@ -52,11 +52,6 @@ enum Pages { name: 'EDIT-CREDIT-CARD-DETAILS', ), permitBiometric(path: 'permit-biometric', name: 'PERMIT-BIOMETRIC'), - - impactGroupDetails( - path: '/impact-group-details', - name: 'IMPACT-GROUP-DETAILS', - ), ; const Pages({ diff --git a/lib/core/enums/amplitude_events.dart b/lib/core/enums/amplitude_events.dart index 645a9ef5b..99e674540 100644 --- a/lib/core/enums/amplitude_events.dart +++ b/lib/core/enums/amplitude_events.dart @@ -218,8 +218,6 @@ enum AmplitudeEvents { nextPermissionsDialogClicked('next_permissions_dialog_clicked'), closePermissionsDialog('close_permissions_dialog'), navigationBarPressed('navigation_bar_pressed'), - impactGroupDetailsReadMoreClicked('impact_group_details_read_more_clicked'), - impactGroupDetailsGiveClicked('impact_group_details_give_clicked'), manageFamilyPressed('manage_family_pressed'), registerWithoutChallengeClicked('register_without_challenge_clicked'), goToChallengeFromRegistrationClicked( diff --git a/lib/features/family/app/family_pages.dart b/lib/features/family/app/family_pages.dart index d504a6361..3fb66613a 100644 --- a/lib/features/family/app/family_pages.dart +++ b/lib/features/family/app/family_pages.dart @@ -77,10 +77,6 @@ enum FamilyPages { path: 'school-event-organisations', name: 'SCHOOL_EVENT_ORGANISATIONS', ), - impactGroupDetails( - path: 'kids-impact-group-details', - name: 'KIDS_IMPACT_GROUP_DETAILS', - ), //reflect and share: reflectIntro(path: 'reflect-intro', name: 'REFLECT-INTRO'), From 6a08f6db5b6912a088ea6198c18b9aea10bef4b0 Mon Sep 17 00:00:00 2001 From: Daniela Damaschin Date: Wed, 6 Nov 2024 10:55:49 +0100 Subject: [PATCH 4/5] kids-1646 parent initial amount 25 --- .../presentation/pages/parent_amount_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/features/family/features/parent_giving_flow/presentation/pages/parent_amount_page.dart b/lib/features/family/features/parent_giving_flow/presentation/pages/parent_amount_page.dart index 8239b3d9c..10ec56acb 100644 --- a/lib/features/family/features/parent_giving_flow/presentation/pages/parent_amount_page.dart +++ b/lib/features/family/features/parent_giving_flow/presentation/pages/parent_amount_page.dart @@ -32,7 +32,7 @@ class ParentAmountPage extends StatefulWidget { } class _ParentAmountPageState extends State { - final initialamount = 5; + final initialamount = 25; late int _amount; @override void initState() { From 2bfc4c021fbd85ac0f55787f8451052bfe789351 Mon Sep 17 00:00:00 2001 From: Daniela Damaschin Date: Thu, 7 Nov 2024 11:57:56 +0100 Subject: [PATCH 5/5] create transaction in cubit not widget --- .../parent_giving_flow/cubit/give_cubit.dart | 19 +++++++++++++++---- .../pages/give_from_list_page.dart | 14 +++++--------- .../presentation/pages/grateful_screen.dart | 13 ++++--------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart b/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart index a20105c0e..f31432820 100644 --- a/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart +++ b/lib/features/family/features/parent_giving_flow/cubit/give_cubit.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:givt_app/core/enums/amplitude_events.dart'; @@ -15,11 +17,20 @@ class GiveCubit extends Cubit { ) : super(GiveInitial()); final CreateTransactionRepository _createTransactionRepository; - Future createTransaction( - {required Transaction transaction, - required String orgName, - required String mediumId}) async { + Future createTransaction({ + required String userId, + required int amount, + required String orgName, + required String mediumId, + bool isGratitude = false, + }) async { emit(GiveLoading()); + final transaction = Transaction( + userId: userId, + amount: amount.toDouble(), + mediumId: base64Encode(utf8.encode(mediumId)), + isActOfService: isGratitude, + ); try { await _createTransactionRepository.createTransaction( transaction: transaction, diff --git a/lib/features/family/features/parent_giving_flow/presentation/pages/give_from_list_page.dart b/lib/features/family/features/parent_giving_flow/presentation/pages/give_from_list_page.dart index e94480f39..9bff294c9 100644 --- a/lib/features/family/features/parent_giving_flow/presentation/pages/give_from_list_page.dart +++ b/lib/features/family/features/parent_giving_flow/presentation/pages/give_from_list_page.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -9,7 +8,6 @@ import 'package:givt_app/core/enums/collect_group_type.dart'; import 'package:givt_app/features/auth/cubit/auth_cubit.dart'; import 'package:givt_app/features/family/app/family_pages.dart'; import 'package:givt_app/features/family/extensions/extensions.dart'; -import 'package:givt_app/features/family/features/giving_flow/create_transaction/models/transaction.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/cubit/give_cubit.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/cubit/medium_cubit.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/presentation/pages/organisation_list_family_page.dart'; @@ -87,13 +85,11 @@ class GiveFromListPage extends StatelessWidget { ), ); await getIt().createTransaction( - transaction: Transaction( - userId: context.read().state.user.guid, - mediumId: base64Encode(utf8.encode(collectGroup.nameSpace)), - amount: result.toDouble(), - ), - orgName: collectGroup.orgName, - mediumId: collectGroup.nameSpace); + userId: context.read().state.user.guid, + amount: result, + orgName: collectGroup.orgName, + mediumId: collectGroup.nameSpace, + ); } } } diff --git a/lib/features/family/features/reflect/presentation/pages/grateful_screen.dart b/lib/features/family/features/reflect/presentation/pages/grateful_screen.dart index adb93f1ce..4cfad6a41 100644 --- a/lib/features/family/features/reflect/presentation/pages/grateful_screen.dart +++ b/lib/features/family/features/reflect/presentation/pages/grateful_screen.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -9,7 +8,6 @@ import 'package:givt_app/features/auth/cubit/auth_cubit.dart'; import 'package:givt_app/features/family/app/injection.dart'; import 'package:givt_app/features/family/extensions/extensions.dart'; import 'package:givt_app/features/family/features/giving_flow/create_transaction/cubit/create_transaction_cubit.dart'; -import 'package:givt_app/features/family/features/giving_flow/create_transaction/models/transaction.dart'; import 'package:givt_app/features/family/features/giving_flow/screens/choose_amount_slider_screen.dart'; import 'package:givt_app/features/family/features/giving_flow/screens/success_screen.dart'; import 'package:givt_app/features/family/features/parent_giving_flow/cubit/give_cubit.dart'; @@ -23,12 +21,12 @@ import 'package:givt_app/features/family/features/reflect/domain/models/game_pro import 'package:givt_app/features/family/features/reflect/presentation/models/grateful_custom.dart'; import 'package:givt_app/features/family/features/reflect/presentation/pages/summary_screen.dart'; import 'package:givt_app/features/family/features/reflect/presentation/widgets/finish_reflection_dialog.dart'; -import 'package:givt_app/features/family/shared/design/components/content/avatar_bar.dart'; import 'package:givt_app/features/family/features/reflect/presentation/widgets/grateful_loading.dart'; import 'package:givt_app/features/family/features/reflect/presentation/widgets/leave_game_button.dart'; import 'package:givt_app/features/family/features/reflect/presentation/widgets/recommendations_widget.dart'; import 'package:givt_app/features/family/features/topup/screens/empty_wallet_bottom_sheet.dart'; import 'package:givt_app/features/family/shared/design/components/components.dart'; +import 'package:givt_app/features/family/shared/design/components/content/avatar_bar.dart'; import 'package:givt_app/features/family/shared/widgets/loading/full_screen_loading_widget.dart'; import 'package:givt_app/features/family/utils/family_app_theme.dart'; import 'package:givt_app/l10n/l10n.dart'; @@ -234,12 +232,9 @@ class _GratefulScreenState extends State { ), ); await _give.createTransaction( - transaction: Transaction( - userId: context.read().state.user.guid, - mediumId: base64Encode(utf8.encode(org.namespace)), - amount: result.toDouble(), - isActOfService: true, - ), + userId: context.read().state.user.guid, + amount: result, + isGratitude: true, orgName: org.name, mediumId: org.namespace, );