diff --git a/assets/icons/icon-navigation-home.png b/assets/icons/icon-navigation-home.png new file mode 100644 index 0000000..58dd8d7 Binary files /dev/null and b/assets/icons/icon-navigation-home.png differ diff --git a/assets/icons/icon-navigation-plan.png b/assets/icons/icon-navigation-plan.png new file mode 100644 index 0000000..261ac03 Binary files /dev/null and b/assets/icons/icon-navigation-plan.png differ diff --git a/assets/icons/icon-navigation-portfolio.png b/assets/icons/icon-navigation-portfolio.png new file mode 100644 index 0000000..f4dd682 Binary files /dev/null and b/assets/icons/icon-navigation-portfolio.png differ diff --git a/assets/icons/icon-navigation-profile.png b/assets/icons/icon-navigation-profile.png new file mode 100644 index 0000000..43a94fc Binary files /dev/null and b/assets/icons/icon-navigation-profile.png differ diff --git a/assets/icons/icon-navigation-transaction.png b/assets/icons/icon-navigation-transaction.png new file mode 100644 index 0000000..2947eea Binary files /dev/null and b/assets/icons/icon-navigation-transaction.png differ diff --git a/assets/icons/icon-remove.png b/assets/icons/icon-remove.png new file mode 100644 index 0000000..1b5b9ab Binary files /dev/null and b/assets/icons/icon-remove.png differ diff --git a/lib/application/assets/path_assets.dart b/lib/application/assets/path_assets.dart index 2431f43..fc3a0ee 100644 --- a/lib/application/assets/path_assets.dart +++ b/lib/application/assets/path_assets.dart @@ -49,6 +49,12 @@ class PathAssets { static const String iconTicket = 'assets/icons/icon-ticket.png'; static const String iconGadget = 'assets/icons/icon-gadget.png'; static const String iconCar = 'assets/icons/icon-car.png'; + static const String iconNavigationHome = 'assets/icons/icon-navigation-home.png'; + static const String iconNavigationPlan = 'assets/icons/icon-navigation-plan.png'; + static const String iconNavigationTransaction = 'assets/icons/icon-navigation-transaction.png'; + static const String iconNavigationPortfolio = 'assets/icons/icon-navigation-portfolio.png'; + static const String iconNavigationProfile = 'assets/icons/icon-navigation-profile.png'; + static const String iconRemove = 'assets/icons/icon-remove.png'; /// IMAGE static const String imgSplashLogo = 'assets/images/splash-logo.png'; @@ -86,4 +92,20 @@ class PathAssets { static const String imgPaymentSuccess = 'assets/images/img-payment-success.png'; static const String frameSignature = 'assets/images/frame-signature.png'; static const String imgFinish = 'assets/images/img-finish.png'; + + static const Map goalInvestIcon = { + 'Education': iconToga, + 'Marriage': iconCake, + 'Old age days': iconHouse, + 'Home': iconHouse, + 'Other Plan': iconCreatePlan, + 'Create Plan': iconCreatePlan, + 'Entertainment': iconTicket, + 'Gadget': iconGadget, + 'Business': iconMarket, + 'Fashion': iconBag, + 'Shop': iconBag, + 'Vehicle': iconCar, + 'Holiday': iconPlane, + }; } diff --git a/lib/application/component/custom_app_bar/custom_app_bar.dart b/lib/application/component/custom_app_bar/custom_app_bar.dart index 727455e..a119939 100644 --- a/lib/application/component/custom_app_bar/custom_app_bar.dart +++ b/lib/application/component/custom_app_bar/custom_app_bar.dart @@ -11,9 +11,9 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { const CustomAppBar({ Key? key, required this.height, - this.leading, required this.title, this.trailing, + this.leading, }) : super(key: key); @override diff --git a/lib/application/component/numeric_pad/numeric_pad.dart b/lib/application/component/numeric_pad/numeric_pad.dart index 959d666..cbf71bf 100644 --- a/lib/application/component/numeric_pad/numeric_pad.dart +++ b/lib/application/component/numeric_pad/numeric_pad.dart @@ -1,3 +1,5 @@ +import 'package:cims_apps/application/assets/path_assets.dart'; +import 'package:cims_apps/application/component/image/image_view.dart'; import 'package:cims_apps/application/theme/color_palette.dart'; import 'package:cims_apps/core/utils/size_config.dart'; import 'package:flutter/material.dart'; @@ -101,8 +103,9 @@ class NumericPad extends StatelessWidget { number, textAlign: TextAlign.center, style: TextStyle( - fontSize: 28, - fontWeight: FontWeight.bold + fontSize: 28, + fontWeight: FontWeight.bold, + color: ColorPalette.slate800 ), ), ), @@ -117,8 +120,9 @@ class NumericPad extends StatelessWidget { onNumberSelected(''); }, child: Icon( - Icons.highlight_remove, + Icons.backspace_outlined, size: 28, + color: ColorPalette.slate800, ), ) ); diff --git a/lib/application/component/radio_agreement.dart b/lib/application/component/radio_agreement.dart new file mode 100644 index 0000000..cecd678 --- /dev/null +++ b/lib/application/component/radio_agreement.dart @@ -0,0 +1,73 @@ +import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:flutter/material.dart'; + +class RadioAgreement extends StatelessWidget { + final void Function() onTap; + final bool isAgree; + final String desc; + const RadioAgreement({super.key, required this.isAgree, required this.desc, required this.onTap,}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GestureDetector( + onTap: onTap, + child: AnimatedContainer( + margin: const EdgeInsets.only(top: 4), + duration: const Duration(milliseconds: 200), + height: 16, + width: 16, + padding: const EdgeInsets.all(1), + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: isAgree + ? ColorPalette.primary + : ColorPalette.slate200)), + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + child: Container( + decoration: BoxDecoration( + color: + isAgree ? ColorPalette.primary : ColorPalette.white, + shape: BoxShape.circle), + ), + ), + ), + ), + const SizedBox( + width: 12, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + desc, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: ColorPalette.slate400), + ), + GestureDetector( + onTap: () {}, + child: const Text( + 'Read More', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + decoration: TextDecoration.underline, + color: ColorPalette.primary), + )) + ], + )) + ], + ), + ); + } +} diff --git a/lib/application/component/subscribe/goal_investing_view.dart b/lib/application/component/subscribe/goal_investing_view.dart index 80c3e53..7c047fd 100644 --- a/lib/application/component/subscribe/goal_investing_view.dart +++ b/lib/application/component/subscribe/goal_investing_view.dart @@ -36,8 +36,8 @@ class GoalInvestingView extends StatelessWidget { routePush( context, page: OtherPlanView( - selectedPlan: (value) { - onListSelected(e.value.title); + selectedPlan: (val) { + onListSelected(val); }, ) ); diff --git a/lib/application/component/subscribe/input_investment_view.dart b/lib/application/component/subscribe/input_investment_view.dart index 846a057..1dd8a22 100644 --- a/lib/application/component/subscribe/input_investment_view.dart +++ b/lib/application/component/subscribe/input_investment_view.dart @@ -54,7 +54,6 @@ class _InputInvestmentViewState extends State { style: TextStyle( fontSize: 20, fontWeight: FontWeight.w700, - ), ), Row( diff --git a/lib/application/component/subscribe/other_plan_view.dart b/lib/application/component/subscribe/other_plan_view.dart index 60bff7a..55204b5 100644 --- a/lib/application/component/subscribe/other_plan_view.dart +++ b/lib/application/component/subscribe/other_plan_view.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:cims_apps/application/assets/path_assets.dart'; import 'package:cims_apps/application/component/button/button_view.dart'; import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart'; @@ -72,6 +74,8 @@ class _OtherPlanViewState extends State { disabled: !(selectedPlan.img != ''), onPressed: () { Navigator.pop(context); + print('haloo'); + print(selectedPlan.name); widget.selectedPlan(selectedPlan.name); }, heightWrapContent: true, @@ -91,6 +95,7 @@ class _OtherPlanViewState extends State { if(plan.name == 'Create Plan'){ showModalBottomSheet( context: context, + isDismissible: false, builder: (context) => modalCreatePlan(), ); } @@ -150,6 +155,9 @@ class _OtherPlanViewState extends State { GestureDetector( onTap: () { Navigator.pop(context); + setState(() { + selectedPlan = Plan('', ''); + }); }, child: Icon(Icons.close_rounded), ) @@ -161,12 +169,12 @@ class _OtherPlanViewState extends State { ), SizedBox(height: 24), ButtonView( - name: 'Select', + name: 'Next', marginVertical: 0, disabled: !(createController.text != ''), onPressed: () { Navigator.of(context)..pop()..pop(); - widget.selectedPlan(selectedPlan.name); + widget.selectedPlan(createController.text); }, heightWrapContent: true, width: SizeConfig.width, diff --git a/lib/application/component/subscribe/total_payment_view.dart b/lib/application/component/subscribe/total_payment_view.dart index 0befdd5..a8ae096 100644 --- a/lib/application/component/subscribe/total_payment_view.dart +++ b/lib/application/component/subscribe/total_payment_view.dart @@ -1,4 +1,5 @@ import 'package:cims_apps/application/component/button/button_view.dart'; +import 'package:cims_apps/application/component/radio_agreement.dart'; import 'package:cims_apps/application/theme/color_palette.dart'; import 'package:cims_apps/core/route/route.dart'; import 'package:cims_apps/core/utils/number_formatter.dart'; @@ -6,22 +7,19 @@ import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; import 'package:flutter/material.dart'; -class TotalPaymentView extends StatefulWidget { +class TotalPaymentView extends StatelessWidget { final int totalInvest; final List listProduct; + final bool isAgree; + final void Function() onTapAgree; const TotalPaymentView({ super.key, required this.listProduct, required this.totalInvest, + required this.isAgree, + required this.onTapAgree, }); - @override - State createState() => _TotalPaymentViewState(); -} - -class _TotalPaymentViewState extends State { - bool isAgreement = false; - @override Widget build(BuildContext context) { return SingleChildScrollView( @@ -49,7 +47,7 @@ class _TotalPaymentViewState extends State { ], ), ), - ...widget.listProduct.asMap().entries.map((e) { + ...listProduct.asMap().entries.map((e) { return Container( padding: const EdgeInsets.only( left: 16, right: 24, bottom: 16, top: 16), @@ -75,7 +73,7 @@ class _TotalPaymentViewState extends State { flex: 7, child: Text( NumberFormatter.numberCurrency( - widget.totalInvest * e.value.totalPercent!, + totalInvest * e.value.totalPercent!, 'Rp ', 'id_ID'), textAlign: TextAlign.end, @@ -129,7 +127,7 @@ class _TotalPaymentViewState extends State { ), Text( NumberFormatter.numberCurrency( - widget.totalInvest, 'Rp ', 'id_ID'), + totalInvest, 'Rp ', 'id_ID'), textAlign: TextAlign.end, style: const TextStyle( fontWeight: FontWeight.w700, @@ -139,7 +137,14 @@ class _TotalPaymentViewState extends State { ], ), ), - buttonAgreement(), + RadioAgreement( + isAgree: isAgree, + desc: 'I agree to buy the mutual fund on this page and have read and agreed to all the contents of the Prospectus and summary information and understand the risks of my investment decision. Read More', + onTap: () { + print('gagaga'); + onTapAgree(); + }, + ), Container( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), child: Row( @@ -154,7 +159,7 @@ class _TotalPaymentViewState extends State { ), Text( NumberFormatter.numberCurrency( - widget.totalInvest, 'Rp ', 'id_ID'), + totalInvest, 'Rp ', 'id_ID'), textAlign: TextAlign.end, style: const TextStyle( fontWeight: FontWeight.w700, @@ -165,16 +170,16 @@ class _TotalPaymentViewState extends State { ), ), ButtonView( - disabled: !isAgreement, + disabled: !isAgree, name: 'Subscribe Now', onPressed: () { routePush(context, page: PaymentMethodView( - totalInvest: widget.totalInvest, + totalInvest: totalInvest, )); }, disabledBgColor: ColorPalette.slate200.withOpacity(0.5), - textColor: isAgreement ? Colors.white : ColorPalette.slate400, + textColor: isAgree ? Colors.white : ColorPalette.slate400, textWeight: FontWeight.w700, textSize: 20, backgroundColor: ColorPalette.primary, @@ -185,71 +190,67 @@ class _TotalPaymentViewState extends State { ); } - Widget buttonAgreement() { - bool isAgree = isAgreement; - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GestureDetector( - onTap: () { - setState(() { - isAgreement = !isAgreement; - }); - }, - child: AnimatedContainer( - margin: const EdgeInsets.only(top: 4), - duration: const Duration(milliseconds: 200), - height: 16, - width: 16, - padding: const EdgeInsets.all(1), - alignment: Alignment.center, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: isAgree - ? ColorPalette.primary - : ColorPalette.slate200)), - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - child: Container( - decoration: BoxDecoration( - color: - isAgree ? ColorPalette.primary : ColorPalette.white, - shape: BoxShape.circle), - ), - ), - ), - ), - const SizedBox( - width: 12, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'I agree to buy the mutual fund on this page and have read and agreed to all the contents of the Prospectus and summary information and understand the risks of my investment decision.', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: ColorPalette.slate400), - ), - GestureDetector( - onTap: () {}, - child: const Text( - 'Read More', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - decoration: TextDecoration.underline, - color: ColorPalette.primary), - )) - ], - )) - ], - ), - ); - } + // Widget buttonAgreement() { + // return Padding( + // padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + // child: Row( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // GestureDetector( + // onTap: () { + // }, + // child: AnimatedContainer( + // margin: const EdgeInsets.only(top: 4), + // duration: const Duration(milliseconds: 200), + // height: 16, + // width: 16, + // padding: const EdgeInsets.all(1), + // alignment: Alignment.center, + // decoration: BoxDecoration( + // shape: BoxShape.circle, + // border: Border.all( + // color: isAgree + // ? ColorPalette.primary + // : ColorPalette.slate200)), + // child: AnimatedContainer( + // duration: const Duration(milliseconds: 200), + // child: Container( + // decoration: BoxDecoration( + // color: + // isAgree ? ColorPalette.primary : ColorPalette.white, + // shape: BoxShape.circle), + // ), + // ), + // ), + // ), + // const SizedBox( + // width: 12, + // ), + // Expanded( + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // const Text( + // 'I agree to buy the mutual fund on this page and have read and agreed to all the contents of the Prospectus and summary information and understand the risks of my investment decision.', + // style: TextStyle( + // fontSize: 16, + // fontWeight: FontWeight.w600, + // color: ColorPalette.slate400), + // ), + // GestureDetector( + // onTap: () {}, + // child: const Text( + // 'Read More', + // style: TextStyle( + // fontSize: 16, + // fontWeight: FontWeight.w600, + // decoration: TextDecoration.underline, + // color: ColorPalette.primary), + // )) + // ], + // )) + // ], + // ), + // ); + // } } diff --git a/lib/application/theme/color_palette.dart b/lib/application/theme/color_palette.dart index 992d6d5..2f4eab5 100644 --- a/lib/application/theme/color_palette.dart +++ b/lib/application/theme/color_palette.dart @@ -92,6 +92,7 @@ class ColorPalette { static const Color green100 = Color(0xFFDCFCE7); static const Color green400 = Color(0xFF4ADE80); static const Color green500 = Color(0xFF16A34A); + static const Color red600 = Color(0xffDC2626); static const Map investTypeColor = { 'Money Market': purple500, diff --git a/lib/features/auth/registration/view/submission_data/risk_profile/question_view.dart b/lib/features/auth/registration/view/submission_data/risk_profile/question_view.dart index 5d38aee..e301cc8 100644 --- a/lib/features/auth/registration/view/submission_data/risk_profile/question_view.dart +++ b/lib/features/auth/registration/view/submission_data/risk_profile/question_view.dart @@ -56,17 +56,24 @@ class _QuestionViewState extends State { bottomNavigationBar: SizedBox( height: 84, child: ButtonView( + disabled: provider.listScore[currentPage] == 0, name: 'Next', marginVertical: 16, + disabledBgColor: ColorPalette.slate200, + textColor: provider.listScore[currentPage] == 0 ? ColorPalette.slate500 : Colors.white, + backgroundColor: ColorPalette.primary, onPressed: () { if (currentPage > 3) { int totalScore = provider.listScore .reduce((value, element) => value + element); provider.setTypeResult(totalScore); routePush(context, - page: ResultsView( - totalScore: totalScore.toString(), - typeResult: provider.typeResult)); + page: ResultsView( + totalScore: totalScore, + typeResult: provider.typeResult + ), + routeType: RouteType.pushReplace + ); } else { setState(() { currentPage += 1; diff --git a/lib/features/auth/registration/view/submission_data/risk_profile/results_view.dart b/lib/features/auth/registration/view/submission_data/risk_profile/results_view.dart index 80d7595..1b9129b 100644 --- a/lib/features/auth/registration/view/submission_data/risk_profile/results_view.dart +++ b/lib/features/auth/registration/view/submission_data/risk_profile/results_view.dart @@ -1,14 +1,17 @@ import 'package:cims_apps/application/component/button/back_button_view.dart'; import 'package:cims_apps/application/component/button/button_view.dart'; +import 'package:cims_apps/application/component/risk_profile.dart'; import 'package:cims_apps/application/theme/color_palette.dart'; import 'package:cims_apps/core/route/route.dart'; import 'package:cims_apps/core/utils/size_config.dart'; +import 'package:cims_apps/features/auth/registration/view/submission_data/risk_profile/question_view.dart'; +import 'package:cims_apps/features/auth/registration/view/submission_data/risk_profile/risk_profile_view.dart'; import 'package:cims_apps/features/auth/registration/view/submission_data/risk_profile/risk_profile_view_model/risk_profile_view_model.dart'; import 'package:cims_apps/features/auth/registration/view/submission_data/terms_and_condition/terms_and_condition_view.dart'; import 'package:flutter/material.dart'; class ResultsView extends StatelessWidget { - final String totalScore; + final int totalScore; final RiskProfileResult typeResult; const ResultsView( {super.key, required this.typeResult, required this.totalScore}); @@ -37,115 +40,15 @@ class ResultsView extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ClipRRect( - borderRadius: BorderRadius.circular(8), - child: Container( - decoration: BoxDecoration( - color: typeResult.color, - image: DecorationImage( - image: AssetImage(typeResult.img), - alignment: Alignment.centerRight)), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - padding: const EdgeInsets.all(24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - typeResult.type, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 24, - color: ColorPalette.white), - ), - const SizedBox( - height: 16, - ), - const Text( - 'Total Score :', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - color: ColorPalette.white), - ), - Text( - totalScore, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 28, - color: ColorPalette.white), - ) - ], - ), - ), - ], - ), - ), - ), - const SizedBox( - height: 24, - ), - Text(typeResult.desc, - style: const TextStyle( - color: ColorPalette.slate500, fontSize: 16)), - const SizedBox( - height: 24, - ), - const Text( - 'Suitable Product', - style: TextStyle( - color: ColorPalette.slate800, - fontWeight: FontWeight.bold, - fontSize: 16), - ), - const SizedBox( - height: 16, - ), - Wrap( - runSpacing: 16, - children: typeResult.suitableProduct.map((e) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6), - border: Border.all(color: ColorPalette.slate200), - ), - child: Row( - children: [ - Container( - padding: const EdgeInsets.all(8), - alignment: Alignment.center, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: typeResult.color.withOpacity(0.1)), - child: Image.asset(e['icon'], - width: SizeConfig.width * 0.07, - color: typeResult.color)), - const SizedBox( - width: 12, - ), - Expanded( - child: Text( - e['desc'], - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: ColorPalette.slate800), - ), - ) - ], - ), - ); - }).toList(), - ), + RiskProfile(totalScore: totalScore, rowSuitableProduct: false), const SizedBox( height: 32, ), ButtonView( name: 'Re-test', - onPressed: () {}, + onPressed: () { + routePush(context, page: QuestionView(), routeType: RouteType.pushReplace); + }, marginVertical: 0, backgroundColor: ColorPalette.white, textColor: ColorPalette.primary, diff --git a/lib/features/bottom_navigation_view.dart b/lib/features/bottom_navigation_view.dart index 99e24c8..2be82d5 100644 --- a/lib/features/bottom_navigation_view.dart +++ b/lib/features/bottom_navigation_view.dart @@ -1,4 +1,6 @@ +import 'package:cims_apps/application/assets/path_assets.dart'; import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:cims_apps/core/utils/size_config.dart'; import 'package:cims_apps/features/dashboard/dashboard_account/view/homepage/homepage_view.dart'; import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view/plan_view.dart'; import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart'; @@ -6,6 +8,12 @@ import 'package:cims_apps/features/profile/view/profile_view.dart'; import 'package:cims_apps/features/transaction/view/transaction_view.dart'; import 'package:flutter/material.dart'; +class BottomNavigationItem { + String icon, label; + + BottomNavigationItem(this.icon, this.label); +} + class BottomNavigationView extends StatefulWidget { const BottomNavigationView({Key? key}) : super(key: key); @@ -26,32 +34,20 @@ class _BottomNavigationViewState extends State { ProfileView(), ]; - List listNavigation = const [ - BottomNavigationBarItem( - icon: Icon(Icons.home_outlined), - label: 'Home', - ), - BottomNavigationBarItem( - icon: Icon(Icons.file_open), - label: 'Plan', - ), - BottomNavigationBarItem( - icon: Icon(Icons.compare_arrows), - label: 'Transaction', - ), - BottomNavigationBarItem( - icon: Icon(Icons.pie_chart_rounded), - label: 'Portfolio', - ), - BottomNavigationBarItem( - icon: Icon(Icons.person), - label: 'Profile', - ), + List listNavigation = [ + BottomNavigationItem(PathAssets.iconNavigationHome, 'Home'), + BottomNavigationItem(PathAssets.iconNavigationPlan, 'Plan'), + BottomNavigationItem(PathAssets.iconNavigationTransaction, 'Transaction'), + BottomNavigationItem(PathAssets.iconNavigationPortfolio, 'Portfolio'), + BottomNavigationItem(PathAssets.iconNavigationProfile, 'Profile') ]; return Scaffold( body: listWidget[_selectedIndex], - bottomNavigationBar: Padding( + bottomNavigationBar: Container( + decoration: const BoxDecoration( + border: Border(top: BorderSide(color: ColorPalette.slate200)) + ), padding: const EdgeInsets.symmetric(vertical: 12), child: BottomNavigationBar( elevation: 0, @@ -61,13 +57,25 @@ class _BottomNavigationViewState extends State { }); }, currentIndex: _selectedIndex, - items: listNavigation, + items: listNavigation.asMap().entries.map((e) { + return BottomNavigationBarItem( + icon: Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Image.asset( + e.value.icon, + width: SizeConfig.width * 0.06, + color: e.key == _selectedIndex ? ColorPalette.primary : ColorPalette.slate800 + ), + ), + label: e.value.label + ); + }).toList(), type: BottomNavigationBarType.fixed, showUnselectedLabels: true, selectedItemColor: ColorPalette.primary, unselectedItemColor: Colors.black, - selectedLabelStyle: const TextStyle(color: ColorPalette.primary), - unselectedLabelStyle: const TextStyle(color: Colors.black), + selectedLabelStyle: const TextStyle(color: ColorPalette.primary, fontSize: 12), + unselectedLabelStyle: const TextStyle(color: Colors.black, fontSize: 12), ), ), ); diff --git a/lib/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart b/lib/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart index a33a7ac..a2f2c39 100644 --- a/lib/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart +++ b/lib/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart @@ -102,7 +102,7 @@ class _InvestTypeViewState extends State { onTap: () { provider.setSelectedProduct(e.value); routePush(context, - page: ProductView(widget.title)); + page: ProductView(selectedProduct: e.value)); }, child: Padding( padding: EdgeInsets.only( diff --git a/lib/features/dashboard/dashboard_account/view/plan/view/plan_view.dart b/lib/features/dashboard/dashboard_account/view/plan/view/plan_view.dart index 664a044..b373824 100644 --- a/lib/features/dashboard/dashboard_account/view/plan/view/plan_view.dart +++ b/lib/features/dashboard/dashboard_account/view/plan/view/plan_view.dart @@ -40,42 +40,50 @@ class _PlanViewState extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: CustomAppBar(height: 70, title: 'Investment Plan'), - body: SingleChildScrollView( - padding: EdgeInsets.all(24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RiskProfile( - totalScore: 26, - rowSuitableProduct: true - ), - SizedBox( - height: 32, - ), - Text('Your Goal in Investing', - style: TextStyle( - fontWeight: FontWeight.w700, - color: ColorPalette.slate800, - fontSize: 18 + return ChangeNotifierProvider( + create: (context) => PlanViewModel(), + child: Scaffold( + appBar: CustomAppBar( + height: SizeConfig.height * 0.08, + title: 'Investment Plan', + leading: SizedBox(), + ), + body: SingleChildScrollView( + padding: EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RiskProfile( + totalScore: 26, + rowSuitableProduct: true ), - ), - SizedBox( - height: 24, - ), - GoalInvestingView( - onListSelected: (p0) { - showModalBottomSheet( - context: context, - isScrollControlled: true, - builder: (context) { - return modalInvest(context, p0); - }, - ); - }, - ) - ], + SizedBox( + height: 32, + ), + Text('Your Goal in Investing', + style: TextStyle( + fontWeight: FontWeight.w700, + color: ColorPalette.slate800, + fontSize: 18 + ), + ), + SizedBox( + height: 24, + ), + GoalInvestingView( + onListSelected: (p0) { + print(p0); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + return modalInvest(context, p0); + }, + ); + }, + ) + ], + ), ), ), ); diff --git a/lib/features/dashboard/dashboard_account/view/plan/view/step_invest_plan/result_options_product.dart b/lib/features/dashboard/dashboard_account/view/plan/view/step_invest_plan/result_options_product.dart index ad54b8c..04deffc 100644 --- a/lib/features/dashboard/dashboard_account/view/plan/view/step_invest_plan/result_options_product.dart +++ b/lib/features/dashboard/dashboard_account/view/plan/view/step_invest_plan/result_options_product.dart @@ -3,9 +3,14 @@ import 'package:cims_apps/application/component/button/button_view.dart'; import 'package:cims_apps/application/component/image/image_view.dart'; import 'package:cims_apps/application/component/subscribe/total_payment_view.dart'; import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:cims_apps/core/route/route.dart'; import 'package:cims_apps/core/utils/size_config.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view/step_invest_plan/options_starting_invest.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view/product_view.dart'; import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class ResultOptionsProduct extends StatelessWidget { final int totalInvest; @@ -19,134 +24,169 @@ class ResultOptionsProduct extends StatelessWidget { Product(name: 'Gemilang Kas 2 Kelas A', type: 'Shares', totalPercent: 0.1) ]; - return Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16) - ), - padding: const EdgeInsets.all(24), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Icon(Icons.arrow_back, color: ColorPalette.slate500), - Text('Results from your risk profile', - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 18, - color: ColorPalette.slate800 - ), - ), - Icon(Icons.close_rounded, color: ColorPalette.slate400) - ], - ), - const SizedBox(height: 32), - SingleChildScrollView( + return ChangeNotifierProvider( + create: (context) => PlanViewModel(), + child: Consumer( + builder: (context, provider, child) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16) + ), + padding: const EdgeInsets.all(24), child: Column( - children: listProduct.asMap().entries.map((e) { - return Container( - margin: const EdgeInsets.only(bottom: 16), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - border: Border.all(color: ColorPalette.slate200), - borderRadius: BorderRadius.circular(12), - boxShadow: const [ - BoxShadow( - color: Color(0XFF1E293B0A) - ) - ] - ), + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + onTap: () { + Navigator.pop(context); + showModalBottomSheet( + context: context, + builder: (context) { + return OptionsStartingInvest(totalInvest: totalInvest); + }, + ); + }, + child: Icon(Icons.arrow_back, color: ColorPalette.slate500) + ), + Text('Results from your risk profile', + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 18, + color: ColorPalette.slate800 + ), + ), + GestureDetector( + onTap: () { + Navigator.pop(context); + + }, + child: Icon(Icons.close_rounded, color: ColorPalette.slate400) + ) + ], + ), + const SizedBox(height: 32), + SingleChildScrollView( child: Column( - children: [ - Row( - children: [ - const ImageView(image: PathAssets.iconGoogle, width: 30,), - const SizedBox( - width: 12, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + children: listProduct.asMap().entries.map((e) { + return Container( + margin: const EdgeInsets.only(bottom: 16), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: ColorPalette.slate200), + borderRadius: BorderRadius.circular(12), + boxShadow: const [ + BoxShadow( + color: Color(0XFF1E293B0A) + ) + ] + ), + child: Column( + children: [ + Row( children: [ - Text(e.value.name ?? '', - style: const TextStyle( - fontWeight: FontWeight.w700, - color: ColorPalette.slate800, + const ImageView(image: PathAssets.iconGoogle, width: 30,), + const SizedBox( + width: 12, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(e.value.name ?? '', + style: const TextStyle( + fontWeight: FontWeight.w700, + color: ColorPalette.slate800, + ), + ), + const SizedBox(height: 4,), + Container( + padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), + decoration: BoxDecoration( + border: Border.all(color: ColorPalette.investTypeColor[e.value.type]!), + color: ColorPalette.investTypeBgColor[e.value.type], + borderRadius: BorderRadius.circular(40) + ), + child: Text(e.value.type ?? '', + style: TextStyle( + color: ColorPalette.investTypeColor[e.value.type], + fontWeight: FontWeight.w600, + fontSize: 12 + ), + ), + ) + ], ), ), - const SizedBox(height: 4,), - Container( - padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), - decoration: BoxDecoration( - border: Border.all(color: ColorPalette.investTypeColor[e.value.type]!), - color: ColorPalette.investTypeBgColor[e.value.type], - borderRadius: BorderRadius.circular(40) - ), - child: Text(e.value.type ?? '', - style: TextStyle( - color: ColorPalette.investTypeColor[e.value.type], - fontWeight: FontWeight.w600, - fontSize: 12 - ), + Text('${(e.value.totalPercent! * 100).toInt()} %', + style: const TextStyle( + fontWeight: FontWeight.w700, + fontSize: 16, + color: ColorPalette.slate800 ), ) ], ), - ), - Text('${(e.value.totalPercent! * 100).toInt()} %', - style: const TextStyle( - fontWeight: FontWeight.w700, - fontSize: 16, - color: ColorPalette.slate800 + const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Divider(height: 1, color: ColorPalette.slate200), ), - ) - ], - ), - const Padding( - padding: EdgeInsets.symmetric(vertical: 16), - child: Divider(height: 1, color: ColorPalette.slate200), - ), - GestureDetector( - onTap: () { - }, - child: const Text('See More', - style: TextStyle( - color: ColorPalette.slate500, - fontWeight: FontWeight.w600, - ), + GestureDetector( + onTap: () { + routePush(context, page: ProductView(selectedProduct: e.value, seeMore: true)); + }, + child: const Text('See More', + style: TextStyle( + color: ColorPalette.slate500, + fontWeight: FontWeight.w600, + ), + ), + ) + ], ), - ) - ], + ); + }).toList(), ), - ); - }).toList(), + ), + const SizedBox( + height: 16, + ), + ButtonView( + name: 'Next', + onPressed: () { + Navigator.pop(context); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) => + ChangeNotifierProvider( + create: (context) => PlanViewModel(), + child: Consumer( + builder: (context, planProvider, _) { + return TotalPaymentView( + listProduct: listProduct, + totalInvest: totalInvest, + isAgree: planProvider.isAgree, + onTapAgree: planProvider.setAgree, + ); + } + ), + ) + ); + }, + width: SizeConfig.width, + heightWrapContent: true, + contentPadding: const EdgeInsets.symmetric(vertical: 16), + marginVertical: 0, + ) + ], ), - ), - const SizedBox( - height: 16, - ), - ButtonView( - name: 'Next', - onPressed: () { - showModalBottomSheet( - context: context, - isScrollControlled: true, - builder: (context) => - TotalPaymentView( - listProduct: listProduct, - totalInvest: totalInvest, - ) - ); - }, - width: SizeConfig.width, - heightWrapContent: true, - contentPadding: const EdgeInsets.symmetric(vertical: 16), - marginVertical: 0, - ) - ], + ); + } ), ); } diff --git a/lib/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart b/lib/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart index 2409e63..1da05fe 100644 --- a/lib/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart +++ b/lib/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart @@ -3,4 +3,10 @@ import 'package:flutter/material.dart'; class PlanViewModel extends ChangeNotifier { List listProduct = []; + bool isAgree = false; + + void setAgree() { + isAgree = !isAgree; + notifyListeners(); + } } \ No newline at end of file diff --git a/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_detail_view.dart b/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_detail_view.dart new file mode 100644 index 0000000..f53f129 --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_detail_view.dart @@ -0,0 +1,258 @@ +import 'package:cims_apps/application/assets/path_assets.dart'; +import 'package:cims_apps/application/component/button/back_button_view.dart'; +import 'package:cims_apps/application/component/button/button_view.dart'; +import 'package:cims_apps/application/component/image/image_view.dart'; +import 'package:cims_apps/application/component/text_title/text_title.dart'; +import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:cims_apps/core/utils/size_config.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/redeem_product.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class PortfolioDetailView extends StatelessWidget { + const PortfolioDetailView({super.key}); + + @override + Widget build(BuildContext context) { + List listProduct = [ + PortfolioProduct( + name: 'Gemilang Dana Kas Maxima', + type: '', + yield: 8.17, + priceUnit: 2600.79, + funds: 6300000), + PortfolioProduct( + name: 'Gemilang Dana Likuid', + type: '', + yield: 6.42, + priceUnit: 1600.79, + funds: 2340000), + PortfolioProduct( + name: 'Gemilang Income Fund', + type: '', + yield: 8.17, + priceUnit: 2600.79, + funds: 6300000) + ]; + + + return MultiProvider( + providers: [ + ChangeNotifierProvider(create: (context) => RedeemProductViewModel()) + ], + child: Scaffold( + backgroundColor: Colors.white, + body: SizedBox( + width: SizeConfig.width, + height: SizeConfig.height, + child: Stack( + children: [ + const ImageView(image: PathAssets.imgDashboardAccount), + Column( + children: [ + const SizedBox( + height: 50, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const BackButtonView(), + const TextTitle(title: 'Education', color: Colors.white), + SizedBox(width: SizeConfig.width * 0.1,) + ], + ), + ), + const SizedBox(height: 24,), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 24), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Portfolio Value', + style: TextStyle( + color: ColorPalette.white, + fontWeight: FontWeight.w400 + ), + ), + TextTitle(title: 'Rp 2.000.000', fontSize: 14, color: Colors.white) + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text('Advantages', + style: TextStyle( + color: ColorPalette.white, + fontWeight: FontWeight.w400 + ), + ), + TextTitle(title: 'Rp 2.000.000', fontSize: 14, color: Colors.white) + ], + ) + ], + ), + ), + const SizedBox(height: 24,), + Expanded( + child: ClipRRect( + borderRadius: BorderRadius.circular(0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.white, + ), + child: ListView( + padding: const EdgeInsets.all(24), + children: [ + cardPortfolio(context) + ], + ), + ), + ) + ) + ], + ) + ], + ), + ), + ), + ); + } + + Widget cardPortfolio(context) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: ColorPalette.slate200), + boxShadow: [ + BoxShadow( + color: const Color(0xff1E293B).withOpacity(0.04), + blurRadius: 8, + spreadRadius: 2 + ) + ] + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ImageView( + image: PathAssets.imgProduct, + width: SizeConfig.width * .13, + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const TextTitle(title: 'Gemilang Dana Kas Maxima', fontSize: 16,), + const SizedBox(height: 4), + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(40), + color: ColorPalette.investTypeBgColor['Money Market']?.withOpacity(0.5) ?? Colors.white, + border: Border.all(width: 2, color: ColorPalette.investTypeColor['Money Market']?.withOpacity(0.4) ?? Colors.white) + ), + child: Text( + 'Money Market' ?? '', + style: TextStyle( + color: ColorPalette.investTypeColor['Money Market'], + fontWeight: FontWeight.w600 + ), + ), + ) + ], + ), + ) + ], + ), + const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Divider(height: 1, color: ColorPalette.slate200,), + ), + Wrap( + runSpacing: 8, + children: [ + rowDescription('Present Value', 'Rp2.660.706', fontWeight: FontWeight.w700), + rowDescription('Investment Capital', 'Rp2.660.706'), + rowDescription('Advantages', 'Rp2.660.706'), + rowDescription('Purchase Price', 'Rp1.500,57'), + rowDescription('Number of Units', '14.002'), + ], + ), + const SizedBox(height: 16,), + Row( + children: [ + Expanded( + child: ButtonView( + name: 'Redeem', + marginVertical: 0, + width: SizeConfig.width, + isOutlined: true, + heightWrapContent: true, + contentPadding: const EdgeInsets.all(12), + backgroundColor: Colors.white, + borderColor: ColorPalette.red600, + textColor: ColorPalette.red600, + onPressed: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + return RedeemProduct(); + }, + ); + }, + ), + ), + const SizedBox(width: 16), + Expanded( + child: ButtonView( + name: 'Buy', + marginVertical: 0, + width: SizeConfig.width, + heightWrapContent: true, + contentPadding: const EdgeInsets.all(12), + onPressed: () { + + }, + ), + ) + ], + ) + ], + ), + ); + } + + Widget rowDescription(String title, String value, {Color? color, FontWeight? fontWeight}) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(title, + style: const TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w600 + ), + ), + Text(value, + style: TextStyle( + color: color ?? ColorPalette.slate800, + fontWeight: fontWeight ?? FontWeight.w600, + ), + ) + ], + ); + } +} diff --git a/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart b/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart index ab4915c..4d14252 100644 --- a/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart +++ b/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart @@ -1,7 +1,10 @@ import 'package:cims_apps/application/assets/path_assets.dart'; import 'package:cims_apps/application/component/image/image_view.dart'; +import 'package:cims_apps/application/component/text_title/text_title.dart'; import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:cims_apps/core/route/route.dart'; import 'package:cims_apps/core/utils/size_config.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/portfolio_detail_view.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; @@ -147,9 +150,31 @@ class _PortofolioViewState extends State { ), menuPortofolio(), const SizedBox( - height: 24, + height: 12, ), - ...listColumnPortofolio(), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TextTitle(title: 'My Portfolio', fontSize: 16), + Row( + children: [ + Icon(Icons.add, size: 18, color: ColorPalette.primary), + SizedBox(width: 4), + const Text('Create', + style: TextStyle( + color: ColorPalette.primary, + fontWeight: FontWeight.w600 + ), + ) + ], + ) + ], + ), + ), + // ...listColumnPortofolio(), + cardPortfolio() ], ), ), @@ -183,6 +208,7 @@ class _PortofolioViewState extends State { seePortofolioValue ? Icons.visibility_off_outlined : Icons.visibility_outlined, + size: 18, color: const Color(0xff93C5FD))) ], ), @@ -358,4 +384,85 @@ class _PortofolioViewState extends State { ); }).toList(); } + + Widget cardPortfolio() { + return GestureDetector( + onTap: () { + routePush(context, page: const PortfolioDetailView()); + }, + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 24), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all(color: ColorPalette.slate200) + ), + child: Column( + children: [ + Row( + children: [ + Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: ColorPalette.blue200.withOpacity(0.5), + borderRadius: BorderRadius.circular(8) + ), + child: ImageView( + image: PathAssets.goalInvestIcon['Education'], + width: SizeConfig.width * 0.07 + ) + ), + const SizedBox(width: 8), + const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextTitle(title: 'Education', fontSize: 16,), + Text('2 Subscriptions', + style: TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w600 + ), + ) + ], + ), + ], + ), + const Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: Divider(height: 1, color: ColorPalette.slate200), + ), + const Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Portfolio Value', + style: TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w400 + ), + ), + TextTitle(title: 'Rp 2.000.000', fontSize: 14,) + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text('Advantages', + style: TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w400 + ), + ), + TextTitle(title: 'Rp 2.000.000', fontSize: 14) + ], + ) + ], + ) + ], + ), + ), + ); + } } diff --git a/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/change_amount.dart b/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/change_amount.dart new file mode 100644 index 0000000..e5d5a0a --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/change_amount.dart @@ -0,0 +1,235 @@ +import 'dart:math'; + +import 'package:cims_apps/application/assets/path_assets.dart'; +import 'package:cims_apps/application/component/button/button_view.dart'; +import 'package:cims_apps/application/component/image/image_view.dart'; +import 'package:cims_apps/application/component/numeric_pad/numeric_pad.dart'; +import 'package:cims_apps/application/component/text_title/text_title.dart'; +import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:cims_apps/core/utils/number_formatter.dart'; +import 'package:cims_apps/core/utils/size_config.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/redeem_product.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ChangeAmount extends StatefulWidget { + final int totalAmount; + const ChangeAmount({super.key, required this.totalAmount}); + + @override + State createState() => _ChangeAmountState(); +} + +class _ChangeAmountState extends State { + TextEditingController amountController = TextEditingController(); + + @override + void initState() { + // TODO: implement initState + super.initState(); + amountController.text = NumberFormatter.numberCurrency(widget.totalAmount, 'Rp ', 'id_ID', decimalDigits: 0); + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + amountController.dispose(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (context) => RedeemProductViewModel(), + child: Consumer( + builder: (context, provider, child) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + onTap: () { + Navigator.pop(context); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + return const RedeemProduct(); + }, + ); + }, + child: const Icon(Icons.arrow_back_rounded) + ), + const Text('Type amount', + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: ColorPalette.slate800 + ), + ), + GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: const Icon(Icons.close_rounded) + ) + ], + ), + ), + const Divider(height: 1, color: ColorPalette.slate200,), + Padding( + padding: EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + cardProduct(), + SizedBox(height: 24), + TextField( + controller: amountController, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 28, + fontWeight: FontWeight.w600, + color: ColorPalette.slate800 + ), + keyboardType: TextInputType.number, + onChanged: (value) { + value = value.replaceAll('Rp ', '').replaceAll('.', ''); + double parseValue = double.parse(value); + if(value.isNotEmpty){ + amountController.text = NumberFormatter.numberCurrency(parseValue, 'Rp ', 'id_ID', decimalDigits: 0); + }else{ + amountController.text = NumberFormatter.numberCurrency(0, 'Rp ', 'id_ID', decimalDigits: 0); + } + }, + decoration: const InputDecoration( + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: ColorPalette.primary, + width: 2 + ), + ) + ), + ), + SizedBox(height: 12), + Text( + 'Min Redeem: ${(NumberFormatter.numberCurrency(10000, 'Rp ', 'id_ID', decimalDigits: 0))}', + style: TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w600, + ), + ), + Text( + 'Max Redeem: ${(NumberFormatter.numberCurrency((provider.getCurrentProduct.priceUnit! * provider.getCurrentProduct.totalUnit!).toInt(), 'Rp ', 'id_ID', decimalDigits: 0))}', + style: TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 24), + NumericPad(onNumberSelected: (p0) { + String checkIsZeroInput = amountController.text.replaceAll('Rp ', '').replaceAll('.', ''); + String getNumeric = p0; + + if(p0.isNotEmpty){ + if(checkIsZeroInput != '0'){ + getNumeric = checkIsZeroInput + getNumeric; + } + }else{ + getNumeric = checkIsZeroInput.substring(0, checkIsZeroInput.length - 1); + } + if(getNumeric.isEmpty){ + getNumeric = '0'; + } + if(double.parse(getNumeric) >= provider.getCurrentProduct.priceUnit! * provider.getCurrentProduct.totalUnit!){ + getNumeric = (provider.getCurrentProduct.priceUnit! * provider.getCurrentProduct.totalUnit!).toString(); + } + String formatNumeric = NumberFormatter.numberCurrency( + double.parse(getNumeric).toInt(), 'Rp ', 'id_ID', decimalDigits: 0); + amountController.text = formatNumeric; + }), + const SizedBox(height: 24), + ButtonView( + name: 'Confirm', + textSize: 20, + marginVertical: 0, + onPressed: () { + String formatValueInput = amountController.text.replaceAll('Rp ', '').replaceAll('.', ''); + provider.setAmount(double.parse(formatValueInput)); + Navigator.pop(context); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + return const RedeemProduct(); + }, + ); + }, + ) + ], + ), + ) + ], + ); + } + ), + ); + } + + Widget cardProduct() { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: ColorPalette.slate200), + boxShadow: [ + BoxShadow( + color: const Color(0xff1E293B).withOpacity(0.04), + blurRadius: 8, + spreadRadius: 2 + ) + ] + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ImageView( + image: PathAssets.imgProduct, + width: SizeConfig.width * .13, + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const TextTitle(title: 'Gemilang Dana Kas Maxima', fontSize: 16,), + const SizedBox(height: 4), + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(40), + color: ColorPalette.investTypeBgColor['Money Market']?.withOpacity(0.5) ?? Colors.white, + border: Border.all(width: 2, color: ColorPalette.investTypeColor['Money Market']?.withOpacity(0.4) ?? Colors.white) + ), + child: Text( + 'Money Market' ?? '', + style: TextStyle( + color: ColorPalette.investTypeColor['Money Market'], + fontWeight: FontWeight.w600 + ), + ), + ) + ], + ), + ) + ], + ), + ); + } +} diff --git a/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/change_destination_account.dart b/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/change_destination_account.dart new file mode 100644 index 0000000..71ca1c5 --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/change_destination_account.dart @@ -0,0 +1,191 @@ +import 'package:cims_apps/application/component/button/button_view.dart'; +import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/redeem_product.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ChangeDestinationAccount extends StatelessWidget { + const ChangeDestinationAccount({super.key}); + + @override + Widget build(BuildContext context) { + List listAccount = [ + Account('Muhamad Rosyidin', 'BRI', '902139012324'), + Account('Achmad Muhaimin', 'BCA', '21391283928') + ]; + + return ChangeNotifierProvider( + create: (context) => RedeemProductViewModel(), + child: Consumer( + builder: (context, provider, child) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + onTap: () { + Navigator.pop(context); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + return const RedeemProduct(); + }, + ); + }, + child: const Icon(Icons.arrow_back_rounded) + ), + const Text('Change Destination Account', + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: ColorPalette.slate800 + ), + ), + GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: const Icon(Icons.close_rounded) + ) + ], + ), + ), + const Divider(height: 1, color: ColorPalette.slate200,), + Padding( + padding: const EdgeInsets.all(24), + child: Column( + children: [ + ...listAccount.asMap().entries.map((e) { + return GestureDetector( + onTap: () => provider.setSelectedAcc(e.value), + child: Padding( + padding: EdgeInsets.only(top: e.key != 0 ? 16 : 0), + child: cardAccount(e.value, provider.selectedAccount?.number ?? provider.getCurrentAccount.number), + ), + ); + }), + const SizedBox(height: 24), + GestureDetector( + child: const Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.add, size: 24, color: ColorPalette.primary), + SizedBox(width: 12,), + Text('New Bank', + style: TextStyle( + color: ColorPalette.primary, + fontSize: 20, + fontWeight: FontWeight.w600 + ), + ) + ], + ), + ), + const SizedBox(height: 32), + ButtonView( + name: 'Save', + textSize: 20, + marginVertical: 0, + onPressed: () { + Navigator.pop(context); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + provider.setCurrentAcc(provider.selectedAccount!); + return const RedeemProduct(); + }, + ); + }, + ) + ], + ), + ), + ], + ); + } + ), + ); + } + + Widget cardAccount(Account account, String numberSelected) { + List listNumber = []; + + List.generate(account.number.length, (index) { + if(index > 3 && index < account.number.length - 4){ + listNumber.add('*'); + }else{ + listNumber.add(account.number[index]); + } + }); + + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(14), + border: Border.all(color: ColorPalette.slate200) + ), + child: Row( + children: [ + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(account.nameOwner, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: ColorPalette.slate800 + ), + ), + Text( + '${account.nameBank} - ${listNumber.join("")}', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: ColorPalette.slate400 + ), + ) + ], + ), + ], + ), + ), + AnimatedContainer( + margin: const EdgeInsets.only(top: 4), + duration: const Duration(milliseconds: 200), + height: 16, + width: 16, + padding: const EdgeInsets.all(1), + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: numberSelected == account.number + ? ColorPalette.primary + : ColorPalette.slate200)), + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + child: Container( + decoration: BoxDecoration( + color: + numberSelected == account.number ? ColorPalette.primary : ColorPalette.white, + shape: BoxShape.circle), + ), + ), + ) + ], + ), + ); + } +} diff --git a/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/redeem_product.dart b/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/redeem_product.dart new file mode 100644 index 0000000..57e2a43 --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/redeem_product.dart @@ -0,0 +1,361 @@ +import 'package:cims_apps/application/assets/path_assets.dart'; +import 'package:cims_apps/application/component/button/button_view.dart'; +import 'package:cims_apps/application/component/image/image_view.dart'; +import 'package:cims_apps/application/component/text_form/text_form_view.dart'; +import 'package:cims_apps/application/component/text_title/text_title.dart'; +import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:cims_apps/core/utils/number_formatter.dart'; +import 'package:cims_apps/core/utils/size_config.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/change_amount.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/change_destination_account.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/total_redeem.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class RedeemProduct extends StatefulWidget { + const RedeemProduct({super.key}); + + @override + State createState() => _RedeemProductState(); +} + +class _RedeemProductState extends State { + TextEditingController amountController = TextEditingController(); + + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + amountController.dispose(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (context) => RedeemProductViewModel(), + child: Consumer( + builder: (context, provider, child) { + double amount = provider.getAmount ?? provider.getCurrentProduct.priceUnit! * provider.getCurrentProduct.totalUnit!; + amountController.text = NumberFormatter.numberCurrency(amount.toInt(), 'Rp ', 'id_ID', decimalDigits: 0); + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('Products to be Redeemed', + style: TextStyle( + fontWeight: FontWeight.w600, + color: ColorPalette.slate800, + fontSize: 16 + ), + ), + GestureDetector( + onTap: () => Navigator.pop(context), + child: const Icon(Icons.close_rounded, color: ColorPalette.slate800,) + ) + ], + ), + ), + const Divider(height: 1, color: ColorPalette.slate200,), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + cardProduct(), + const SizedBox(height: 16), + segmentAmount( + context, + provider.getAmount ?? provider.getCurrentProduct.priceUnit! * (provider.getCurrentProduct.totalUnit! / 2.0), + provider.getUnit ?? provider.getCurrentProduct.totalUnit! / 2.0, + (value) { + provider.setUnit(value); + }, + ), + const SizedBox(height: 16), + segmentDestinationAcc(provider.getCurrentAccount), + const SizedBox(height: 36), + ButtonView( + name: 'Redeem', + textSize: 20, + marginVertical: 0, + onPressed: () { + Navigator.pop(context); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + return TotalRedeem(); + }, + ); + }, + ), + const SizedBox(height: 16) + ], + ), + ) + ], + ); + } + ), + ); + } + + Widget cardProduct() { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: ColorPalette.slate200), + boxShadow: [ + BoxShadow( + color: const Color(0xff1E293B).withOpacity(0.04), + blurRadius: 8, + spreadRadius: 2 + ) + ] + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ImageView( + image: PathAssets.imgProduct, + width: SizeConfig.width * .13, + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const TextTitle(title: 'Gemilang Dana Kas Maxima', fontSize: 16,), + const SizedBox(height: 4), + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(40), + color: ColorPalette.investTypeBgColor['Money Market']?.withOpacity(0.5) ?? Colors.white, + border: Border.all(width: 2, color: ColorPalette.investTypeColor['Money Market']?.withOpacity(0.4) ?? Colors.white) + ), + child: Text( + 'Money Market' ?? '', + style: TextStyle( + color: ColorPalette.investTypeColor['Money Market'], + fontWeight: FontWeight.w600 + ), + ), + ) + ], + ), + ) + ], + ), + ); + } + + Widget segmentAmount(context, double currentAmount, double currentUnit, void Function(double value) setUnit) { + double sliderValue = currentUnit / Provider.of(context, listen: false).getCurrentProduct.totalUnit!; + return Column( + children: [ + const Align( + alignment: Alignment.centerLeft, + child: Text('Amount', + style: TextStyle( + fontWeight: FontWeight.w600, + color: ColorPalette.slate800, + fontSize: 16 + ), + ), + ), + TextField( + controller: amountController, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 28, + fontWeight: FontWeight.w700, + color: ColorPalette.slate800 + ), + keyboardType: TextInputType.number, + readOnly: true, + decoration: InputDecoration( + enabledBorder: const UnderlineInputBorder( + borderSide: BorderSide( + color: ColorPalette.slate200, + width: 1 + ), + ), + suffixIcon: GestureDetector( + onTap: () { + Navigator.pop(context); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + return ChangeAmount( + totalAmount: currentAmount.toInt(), + ); + }, + ); + }, + child: const Icon(Icons.edit, color: ColorPalette.primary), + ) + ), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(currentUnit.toStringAsFixed(2).replaceAll('.', ','), + style: const TextStyle( + fontWeight: FontWeight.w700, + fontSize: 18, + color: ColorPalette.slate800 + ), + ), + const Text(' unit', + style: TextStyle( + fontWeight: FontWeight.w600, + color: ColorPalette.slate400 + ), + ) + ], + ), + ), + Row( + children: [ + Expanded( + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 4.0, + thumbColor: ColorPalette.primary, + thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 10.0), + overlayColor:Colors.deepPurple, + inactiveTickMarkColor: ColorPalette.primary, + inactiveTrackColor: ColorPalette.slate200, + overlayShape: SliderComponentShape.noOverlay + ), + child: Slider( + value: sliderValue, + onChanged: setUnit, + label: sliderValue.round().toString(), + ), + ), + ), + SizedBox(width: 12), + Text('${(sliderValue * 100).toStringAsFixed(2)} %', + style: const TextStyle( + color: ColorPalette.slate800, + fontWeight: FontWeight.w600 + ), + ) + ], + ) + ], + ); + } + + Widget segmentDestinationAcc(Account account) { + List listNumber = []; + + List.generate(account.number.length, (index) { + if(index > 3 && index < account.number.length - 4){ + listNumber.add('*'); + }else{ + listNumber.add(account.number[index]); + } + }); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('Destination Account', + style: TextStyle( + fontWeight: FontWeight.w600, + color: ColorPalette.slate800, + fontSize: 16 + ), + ), + const SizedBox(height: 16), + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(14), + border: Border.all(color: ColorPalette.slate200) + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(account.nameOwner, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: ColorPalette.slate800 + ), + ), + Text('${account.nameBank} - ${listNumber.join("")}', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: ColorPalette.slate400 + ), + ) + ], + ), + ], + ), + ), + GestureDetector( + onTap: () { + Navigator.pop(context); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) => const ChangeDestinationAccount(), + ); + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + color: ColorPalette.blue200.withOpacity(0.5) + ), + child: const Row( + children: [ + Icon(Icons.change_circle_outlined, color: ColorPalette.primary, size: 20), + SizedBox(width: 4), + Text('Change', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: ColorPalette.primary + ), + ) + ], + ), + ), + ) + ], + ), + ) + ], + ); + } +} diff --git a/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/total_redeem.dart b/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/total_redeem.dart new file mode 100644 index 0000000..33e6e8f --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/total_redeem.dart @@ -0,0 +1,205 @@ +import 'package:cims_apps/application/assets/path_assets.dart'; +import 'package:cims_apps/application/component/button/button_view.dart'; +import 'package:cims_apps/application/component/image/image_view.dart'; +import 'package:cims_apps/application/component/radio_agreement.dart'; +import 'package:cims_apps/application/component/text_title/text_title.dart'; +import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:cims_apps/core/utils/number_formatter.dart'; +import 'package:cims_apps/core/utils/size_config.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class TotalRedeem extends StatelessWidget { + const TotalRedeem({super.key}); + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (context) => RedeemProductViewModel(), + child: Consumer( + builder: (context, provider, child) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('Investment Funds that You Cash Out', + style: TextStyle( + fontWeight: FontWeight.w600, + color: ColorPalette.slate800, + fontSize: 16 + ), + ), + GestureDetector( + onTap: () => Navigator.pop(context), + child: const Icon(Icons.close_rounded, color: ColorPalette.slate800,) + ) + ], + ), + ), + const Divider(height: 1, color: ColorPalette.slate200,), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + child: cardProduct(provider.getCurrentProduct, provider.getUnit!), + ), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 24), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Sales Commission', + style: TextStyle( + color: ColorPalette.slate400, + fontSize: 16 + ), + ), + Text('Free', + style: TextStyle( + fontWeight: FontWeight.w600, + color: ColorPalette.primary, + fontSize: 16 + ), + ) + ], + ), + ), + const SizedBox(height: 16), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 24), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Cash Out Method', + style: TextStyle( + color: ColorPalette.slate400, + fontSize: 16 + ), + ), + Text('Regular', + style: TextStyle( + fontWeight: FontWeight.w600, + color: ColorPalette.primary, + fontSize: 16 + ), + ) + ], + ), + ), + const SizedBox(height: 16,), + Container( + padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16), + color: ColorPalette.slate200.withOpacity(0.5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: TextTitle( + title: 'Estimated Funds Disbursed', + color: ColorPalette.slate500, + fontSize: 16, + ) + ), + Expanded( + child: Text( + NumberFormatter.numberCurrency((provider.getCurrentProduct.priceUnit! * provider.getUnit!).toInt(), 'Rp ', 'id_ID', decimalDigits: 0), + textAlign: TextAlign.end, + style: TextStyle( + color: ColorPalette.slate800, + fontWeight: FontWeight.w700, + fontSize: 18 + ), + ) + ) + ], + ), + ), + RadioAgreement( + isAgree: provider.isAgree, + desc: 'I agree to the sale of the mutual funds listed on this page. I understand that the total funds disbursed are approximate. The amount received may change according to the closing price of the mutual fund on the day of sale.', + onTap: provider.setAgree + ), + const SizedBox(height: 24), + ButtonView( + disabled: !provider.isAgree, + name: 'Redeem', + textSize: 20, + marginVertical: 0, + disabledBgColor: ColorPalette.slate200.withOpacity(0.5), + textColor: !provider.isAgree ? ColorPalette.slate400 : Colors.white, + onPressed: () { + Navigator.pop(context); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) { + return TotalRedeem(); + }, + ); + }, + ), + const SizedBox(height: 24) + ], + ); + } + ), + ); + } + + Widget cardProduct(PortfolioProduct product, double currentUnit) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: ColorPalette.slate200), + boxShadow: [ + BoxShadow( + color: const Color(0xff1E293B).withOpacity(0.04), + blurRadius: 8, + spreadRadius: 2 + ) + ] + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ImageView( + image: PathAssets.imgProduct, + width: SizeConfig.width * .13, + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextTitle(title: product.name ?? '', fontSize: 16,), + const SizedBox(height: 4), + Row( + children: [ + Text(currentUnit.toStringAsFixed(2).replaceAll('.', ','), + style: const TextStyle( + fontWeight: FontWeight.w700, + fontSize: 18, + color: ColorPalette.slate800 + ), + ), + const Text(' unit', + style: TextStyle( + fontWeight: FontWeight.w600, + color: ColorPalette.slate400 + ), + ) + ], + ), + ], + ), + ) + ], + ), + ); + } +} diff --git a/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart b/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart new file mode 100644 index 0000000..e150e1e --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; + +class Account { + String nameOwner, nameBank, number; + + Account(this.nameOwner, this.nameBank, this.number); +} + +class PortfolioProduct { + String? name, type; + double? yield; + double? priceUnit, funds, totalPercent, totalUnit; + + PortfolioProduct({this.name, this.type, this.yield, this.priceUnit, this.funds, this.totalPercent = 1, this.totalUnit}); +} + +class RedeemProductViewModel extends ChangeNotifier { + static Account currentAccount = Account('Muhamad Rosyidin', 'BRI', '902139012324'); + static PortfolioProduct currentProduct = + PortfolioProduct( + name: 'Gemilang Dana Kas Maxima', + type: '', + yield: 8.17, + priceUnit: 2600.79, + funds: 6300000, + totalUnit: 25 + ); + + static double? amount; + static double? unit; + Account? selectedAccount; + + Account get getCurrentAccount => currentAccount; + PortfolioProduct get getCurrentProduct => currentProduct; + double? get getAmount => amount; + double? get getUnit => unit; + + bool isAgree = false; + + void setCurrentAcc(Account account) { + currentAccount = account; + notifyListeners(); + } + + void setSelectedAcc(Account account){ + selectedAccount = account; + notifyListeners(); + } + + void setAmount(double amount) { + amount = amount; + unit = (amount / currentProduct.priceUnit!); + notifyListeners(); + } + + void setUnit(double value){ + unit = currentProduct.totalUnit! * value; + amount = unit! * currentProduct.priceUnit!; + notifyListeners(); + } + + void setProduct(PortfolioProduct product) { + currentProduct = product; + notifyListeners(); + } + + void setAgree() { + isAgree = !isAgree; + notifyListeners(); + } +} \ No newline at end of file diff --git a/lib/features/dashboard/dashboard_account/view/product/view/product_view.dart b/lib/features/dashboard/dashboard_account/view/product/view/product_view.dart index 40438e1..9ccf953 100644 --- a/lib/features/dashboard/dashboard_account/view/product/view/product_view.dart +++ b/lib/features/dashboard/dashboard_account/view/product/view/product_view.dart @@ -24,8 +24,9 @@ class Time { } class ProductView extends StatefulWidget { - final String investType; - const ProductView(this.investType, {super.key}); + final bool seeMore; + final Product selectedProduct; + const ProductView({super.key, required this.selectedProduct, this.seeMore = false}); @override State createState() => _ProductViewState(); @@ -144,22 +145,23 @@ class _ProductViewState extends State { ], ), ), - bottomNavigationBar: Container( - height: SizeConfig.height * .1, - padding: const EdgeInsets.symmetric(horizontal: 24), - child: ButtonView( - name: 'Subscribe', - onPressed: () { - showModalBottomSheet( - context: context, - isScrollControlled: true, - builder: (context) => SelectGoalInvesting(), - ); - }, - height: SizeConfig.height * 0.06, - marginVertical: 16, - ), - ), + bottomNavigationBar: !widget.seeMore ? + Container( + height: SizeConfig.height * .1, + padding: const EdgeInsets.symmetric(horizontal: 24), + child: ButtonView( + name: 'Subscribe', + onPressed: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) => SelectGoalInvesting(), + ); + }, + height: SizeConfig.height * 0.06, + marginVertical: 16, + ), + ) : SizedBox(), ), ); } @@ -177,7 +179,7 @@ class _ProductViewState extends State { SizedBox(width: 8), Expanded( child: Text( - 'Gemilang Dana Kas Maxima', + widget.selectedProduct.name ?? '', maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( @@ -190,17 +192,18 @@ class _ProductViewState extends State { ], ), ), + SizedBox(width: 12), Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( borderRadius: BorderRadius.circular(40), - color: ColorPalette.investTypeBgColor[widget.investType] ?? Colors.white, - border: Border.all(width: 2, color: ColorPalette.investTypeColor[widget.investType] ?? Colors.white) + color: ColorPalette.investTypeBgColor[widget.selectedProduct.type] ?? Colors.white, + border: Border.all(width: 2, color: ColorPalette.investTypeColor[widget.selectedProduct.type] ?? Colors.white) ), child: Text( - widget.investType, + widget.selectedProduct.type ?? '', style: TextStyle( - color: ColorPalette.investTypeColor[widget.investType], + color: ColorPalette.investTypeColor[widget.selectedProduct.type], fontWeight: FontWeight.w600 ), ), diff --git a/lib/features/dashboard/dashboard_account/view/product/view/step_subscribe/select_goal_investing.dart b/lib/features/dashboard/dashboard_account/view/product/view/step_subscribe/select_goal_investing.dart index 5b3d081..f21532f 100644 --- a/lib/features/dashboard/dashboard_account/view/product/view/step_subscribe/select_goal_investing.dart +++ b/lib/features/dashboard/dashboard_account/view/product/view/step_subscribe/select_goal_investing.dart @@ -2,6 +2,7 @@ import 'package:cims_apps/application/component/subscribe/goal_investing_view.da import 'package:cims_apps/application/component/subscribe/input_investment_view.dart'; import 'package:cims_apps/application/component/subscribe/total_payment_view.dart'; import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart'; import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -11,10 +12,9 @@ class SelectGoalInvesting extends StatelessWidget { @override Widget build(BuildContext context) { - return MultiProvider( - providers: [ - ChangeNotifierProvider(create: (context) => ProductViewModel(),) - ], + + return ChangeNotifierProvider( + create: (context) => ProductViewModel(), child: Consumer( builder: (context, provider, child) { return Container( @@ -51,23 +51,39 @@ class SelectGoalInvesting extends StatelessWidget { context: context, isScrollControlled: true, builder: (context) { - return InputInvestmentView( - selectedPlan: p0, - nextMove: (value) { - Navigator.pop(context); - int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll(',', '')); - showModalBottomSheet( - context: context, - isScrollControlled: true, - builder: (context) => - TotalPaymentView( - listProduct: [ - provider.getSelectedProduct - ], - totalInvest: formatIntParse, - ) - ); - }, + return ChangeNotifierProvider( + create: (context) => ProductViewModel(), + child: Consumer( + builder: (context, provider, child) { + return InputInvestmentView( + selectedPlan: p0, + nextMove: (value) { + Navigator.pop(context); + int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll(',', '')); + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) => + ChangeNotifierProvider( + create: (context) => ProductViewModel(), + child: Consumer( + builder: (context, provider, child) { + return TotalPaymentView( + listProduct: [ + provider.getSelectedProduct + ], + totalInvest: formatIntParse, + isAgree: provider.isAgree, + onTapAgree: provider.setAgree, + ); + } + ), + ) + ); + }, + ); + } + ), ); }, ); diff --git a/lib/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart b/lib/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart index e7fddea..7835916 100644 --- a/lib/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart +++ b/lib/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart @@ -14,6 +14,7 @@ class ProductViewModel extends ChangeNotifier { Product get getSelectedProduct => selectedProduct; double totalInvestment = 0; + bool isAgree = false; void setSelectedProduct(Product product) { selectedProduct = product; @@ -24,4 +25,9 @@ class ProductViewModel extends ChangeNotifier { totalInvestment = value; notifyListeners(); } + + void setAgree() { + isAgree = !isAgree; + notifyListeners(); + } } \ No newline at end of file diff --git a/lib/features/profile/view/profile_view.dart b/lib/features/profile/view/profile_view.dart index a62fc59..fac17ac 100644 --- a/lib/features/profile/view/profile_view.dart +++ b/lib/features/profile/view/profile_view.dart @@ -8,7 +8,7 @@ class ProfileView extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: CustomAppBar(height: SizeConfig.height * .1, title: 'Profile'), + appBar: CustomAppBar(height: SizeConfig.height * .08, title: 'Profile'), ); } } diff --git a/lib/features/transaction/view/transaction_view.dart b/lib/features/transaction/view/transaction_view.dart index 1059f1d..8a9b14b 100644 --- a/lib/features/transaction/view/transaction_view.dart +++ b/lib/features/transaction/view/transaction_view.dart @@ -8,8 +8,7 @@ class TransactionView extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: - CustomAppBar(height: SizeConfig.height * .1, title: 'Transaction'), + appBar: CustomAppBar(height: SizeConfig.height * 0.08, title: 'Transaction'), ); } }