Merge pull request 'yoga' (#16) from yoga into dev

Reviewed-on: #16
This commit is contained in:
Prajna Prayoga 2024-02-22 14:46:52 +07:00
commit a6ea9a2314
34 changed files with 1957 additions and 425 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 899 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -49,6 +49,12 @@ class PathAssets {
static const String iconTicket = 'assets/icons/icon-ticket.png'; static const String iconTicket = 'assets/icons/icon-ticket.png';
static const String iconGadget = 'assets/icons/icon-gadget.png'; static const String iconGadget = 'assets/icons/icon-gadget.png';
static const String iconCar = 'assets/icons/icon-car.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 /// IMAGE
static const String imgSplashLogo = 'assets/images/splash-logo.png'; 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 imgPaymentSuccess = 'assets/images/img-payment-success.png';
static const String frameSignature = 'assets/images/frame-signature.png'; static const String frameSignature = 'assets/images/frame-signature.png';
static const String imgFinish = 'assets/images/img-finish.png'; static const String imgFinish = 'assets/images/img-finish.png';
static const Map<String, String> 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,
};
} }

View File

@ -11,9 +11,9 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
const CustomAppBar({ const CustomAppBar({
Key? key, Key? key,
required this.height, required this.height,
this.leading,
required this.title, required this.title,
this.trailing, this.trailing,
this.leading,
}) : super(key: key); }) : super(key: key);
@override @override

View File

@ -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/application/theme/color_palette.dart';
import 'package:cims_apps/core/utils/size_config.dart'; import 'package:cims_apps/core/utils/size_config.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -101,8 +103,9 @@ class NumericPad extends StatelessWidget {
number, number,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 28, fontSize: 28,
fontWeight: FontWeight.bold fontWeight: FontWeight.bold,
color: ColorPalette.slate800
), ),
), ),
), ),
@ -117,8 +120,9 @@ class NumericPad extends StatelessWidget {
onNumberSelected(''); onNumberSelected('');
}, },
child: Icon( child: Icon(
Icons.highlight_remove, Icons.backspace_outlined,
size: 28, size: 28,
color: ColorPalette.slate800,
), ),
) )
); );

View File

@ -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),
))
],
))
],
),
);
}
}

View File

@ -36,8 +36,8 @@ class GoalInvestingView extends StatelessWidget {
routePush( routePush(
context, context,
page: OtherPlanView( page: OtherPlanView(
selectedPlan: (value) { selectedPlan: (val) {
onListSelected(e.value.title); onListSelected(val);
}, },
) )
); );

View File

@ -54,7 +54,6 @@ class _InputInvestmentViewState extends State<InputInvestmentView> {
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
), ),
), ),
Row( Row(

View File

@ -1,3 +1,5 @@
import 'dart:math';
import 'package:cims_apps/application/assets/path_assets.dart'; 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/button/button_view.dart';
import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart'; import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart';
@ -72,6 +74,8 @@ class _OtherPlanViewState extends State<OtherPlanView> {
disabled: !(selectedPlan.img != ''), disabled: !(selectedPlan.img != ''),
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
print('haloo');
print(selectedPlan.name);
widget.selectedPlan(selectedPlan.name); widget.selectedPlan(selectedPlan.name);
}, },
heightWrapContent: true, heightWrapContent: true,
@ -91,6 +95,7 @@ class _OtherPlanViewState extends State<OtherPlanView> {
if(plan.name == 'Create Plan'){ if(plan.name == 'Create Plan'){
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isDismissible: false,
builder: (context) => modalCreatePlan(), builder: (context) => modalCreatePlan(),
); );
} }
@ -150,6 +155,9 @@ class _OtherPlanViewState extends State<OtherPlanView> {
GestureDetector( GestureDetector(
onTap: () { onTap: () {
Navigator.pop(context); Navigator.pop(context);
setState(() {
selectedPlan = Plan('', '');
});
}, },
child: Icon(Icons.close_rounded), child: Icon(Icons.close_rounded),
) )
@ -161,12 +169,12 @@ class _OtherPlanViewState extends State<OtherPlanView> {
), ),
SizedBox(height: 24), SizedBox(height: 24),
ButtonView( ButtonView(
name: 'Select', name: 'Next',
marginVertical: 0, marginVertical: 0,
disabled: !(createController.text != ''), disabled: !(createController.text != ''),
onPressed: () { onPressed: () {
Navigator.of(context)..pop()..pop(); Navigator.of(context)..pop()..pop();
widget.selectedPlan(selectedPlan.name); widget.selectedPlan(createController.text);
}, },
heightWrapContent: true, heightWrapContent: true,
width: SizeConfig.width, width: SizeConfig.width,

View File

@ -1,4 +1,5 @@
import 'package:cims_apps/application/component/button/button_view.dart'; 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/application/theme/color_palette.dart';
import 'package:cims_apps/core/route/route.dart'; import 'package:cims_apps/core/route/route.dart';
import 'package:cims_apps/core/utils/number_formatter.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:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class TotalPaymentView extends StatefulWidget { class TotalPaymentView extends StatelessWidget {
final int totalInvest; final int totalInvest;
final List<Product> listProduct; final List<Product> listProduct;
final bool isAgree;
final void Function() onTapAgree;
const TotalPaymentView({ const TotalPaymentView({
super.key, super.key,
required this.listProduct, required this.listProduct,
required this.totalInvest, required this.totalInvest,
required this.isAgree,
required this.onTapAgree,
}); });
@override
State<TotalPaymentView> createState() => _TotalPaymentViewState();
}
class _TotalPaymentViewState extends State<TotalPaymentView> {
bool isAgreement = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleChildScrollView( return SingleChildScrollView(
@ -49,7 +47,7 @@ class _TotalPaymentViewState extends State<TotalPaymentView> {
], ],
), ),
), ),
...widget.listProduct.asMap().entries.map((e) { ...listProduct.asMap().entries.map((e) {
return Container( return Container(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 16, right: 24, bottom: 16, top: 16), left: 16, right: 24, bottom: 16, top: 16),
@ -75,7 +73,7 @@ class _TotalPaymentViewState extends State<TotalPaymentView> {
flex: 7, flex: 7,
child: Text( child: Text(
NumberFormatter.numberCurrency( NumberFormatter.numberCurrency(
widget.totalInvest * e.value.totalPercent!, totalInvest * e.value.totalPercent!,
'Rp ', 'Rp ',
'id_ID'), 'id_ID'),
textAlign: TextAlign.end, textAlign: TextAlign.end,
@ -129,7 +127,7 @@ class _TotalPaymentViewState extends State<TotalPaymentView> {
), ),
Text( Text(
NumberFormatter.numberCurrency( NumberFormatter.numberCurrency(
widget.totalInvest, 'Rp ', 'id_ID'), totalInvest, 'Rp ', 'id_ID'),
textAlign: TextAlign.end, textAlign: TextAlign.end,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
@ -139,7 +137,14 @@ class _TotalPaymentViewState extends State<TotalPaymentView> {
], ],
), ),
), ),
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( Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row( child: Row(
@ -154,7 +159,7 @@ class _TotalPaymentViewState extends State<TotalPaymentView> {
), ),
Text( Text(
NumberFormatter.numberCurrency( NumberFormatter.numberCurrency(
widget.totalInvest, 'Rp ', 'id_ID'), totalInvest, 'Rp ', 'id_ID'),
textAlign: TextAlign.end, textAlign: TextAlign.end,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
@ -165,16 +170,16 @@ class _TotalPaymentViewState extends State<TotalPaymentView> {
), ),
), ),
ButtonView( ButtonView(
disabled: !isAgreement, disabled: !isAgree,
name: 'Subscribe Now', name: 'Subscribe Now',
onPressed: () { onPressed: () {
routePush(context, routePush(context,
page: PaymentMethodView( page: PaymentMethodView(
totalInvest: widget.totalInvest, totalInvest: totalInvest,
)); ));
}, },
disabledBgColor: ColorPalette.slate200.withOpacity(0.5), disabledBgColor: ColorPalette.slate200.withOpacity(0.5),
textColor: isAgreement ? Colors.white : ColorPalette.slate400, textColor: isAgree ? Colors.white : ColorPalette.slate400,
textWeight: FontWeight.w700, textWeight: FontWeight.w700,
textSize: 20, textSize: 20,
backgroundColor: ColorPalette.primary, backgroundColor: ColorPalette.primary,
@ -185,71 +190,67 @@ class _TotalPaymentViewState extends State<TotalPaymentView> {
); );
} }
Widget buttonAgreement() { // Widget buttonAgreement() {
bool isAgree = isAgreement; // return Padding(
return Padding( // padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), // child: Row(
child: Row( // crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, // children: [
children: [ // GestureDetector(
GestureDetector( // onTap: () {
onTap: () { // },
setState(() { // child: AnimatedContainer(
isAgreement = !isAgreement; // margin: const EdgeInsets.only(top: 4),
}); // duration: const Duration(milliseconds: 200),
}, // height: 16,
child: AnimatedContainer( // width: 16,
margin: const EdgeInsets.only(top: 4), // padding: const EdgeInsets.all(1),
duration: const Duration(milliseconds: 200), // alignment: Alignment.center,
height: 16, // decoration: BoxDecoration(
width: 16, // shape: BoxShape.circle,
padding: const EdgeInsets.all(1), // border: Border.all(
alignment: Alignment.center, // color: isAgree
decoration: BoxDecoration( // ? ColorPalette.primary
shape: BoxShape.circle, // : ColorPalette.slate200)),
border: Border.all( // child: AnimatedContainer(
color: isAgree // duration: const Duration(milliseconds: 200),
? ColorPalette.primary // child: Container(
: ColorPalette.slate200)), // decoration: BoxDecoration(
child: AnimatedContainer( // color:
duration: const Duration(milliseconds: 200), // isAgree ? ColorPalette.primary : ColorPalette.white,
child: Container( // shape: BoxShape.circle),
decoration: BoxDecoration( // ),
color: // ),
isAgree ? ColorPalette.primary : ColorPalette.white, // ),
shape: BoxShape.circle), // ),
), // const SizedBox(
), // width: 12,
), // ),
), // Expanded(
const SizedBox( // child: Column(
width: 12, // crossAxisAlignment: CrossAxisAlignment.start,
), // children: [
Expanded( // const Text(
child: Column( // '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.',
crossAxisAlignment: CrossAxisAlignment.start, // style: TextStyle(
children: [ // fontSize: 16,
const Text( // fontWeight: FontWeight.w600,
'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.', // color: ColorPalette.slate400),
style: TextStyle( // ),
fontSize: 16, // GestureDetector(
fontWeight: FontWeight.w600, // onTap: () {},
color: ColorPalette.slate400), // child: const Text(
), // 'Read More',
GestureDetector( // style: TextStyle(
onTap: () {}, // fontSize: 16,
child: const Text( // fontWeight: FontWeight.w600,
'Read More', // decoration: TextDecoration.underline,
style: TextStyle( // color: ColorPalette.primary),
fontSize: 16, // ))
fontWeight: FontWeight.w600, // ],
decoration: TextDecoration.underline, // ))
color: ColorPalette.primary), // ],
)) // ),
], // );
)) // }
],
),
);
}
} }

View File

@ -92,6 +92,7 @@ class ColorPalette {
static const Color green100 = Color(0xFFDCFCE7); static const Color green100 = Color(0xFFDCFCE7);
static const Color green400 = Color(0xFF4ADE80); static const Color green400 = Color(0xFF4ADE80);
static const Color green500 = Color(0xFF16A34A); static const Color green500 = Color(0xFF16A34A);
static const Color red600 = Color(0xffDC2626);
static const Map<String, Color> investTypeColor = { static const Map<String, Color> investTypeColor = {
'Money Market': purple500, 'Money Market': purple500,

View File

@ -56,17 +56,24 @@ class _QuestionViewState extends State<QuestionView> {
bottomNavigationBar: SizedBox( bottomNavigationBar: SizedBox(
height: 84, height: 84,
child: ButtonView( child: ButtonView(
disabled: provider.listScore[currentPage] == 0,
name: 'Next', name: 'Next',
marginVertical: 16, marginVertical: 16,
disabledBgColor: ColorPalette.slate200,
textColor: provider.listScore[currentPage] == 0 ? ColorPalette.slate500 : Colors.white,
backgroundColor: ColorPalette.primary,
onPressed: () { onPressed: () {
if (currentPage > 3) { if (currentPage > 3) {
int totalScore = provider.listScore int totalScore = provider.listScore
.reduce((value, element) => value + element); .reduce((value, element) => value + element);
provider.setTypeResult(totalScore); provider.setTypeResult(totalScore);
routePush(context, routePush(context,
page: ResultsView( page: ResultsView(
totalScore: totalScore.toString(), totalScore: totalScore,
typeResult: provider.typeResult)); typeResult: provider.typeResult
),
routeType: RouteType.pushReplace
);
} else { } else {
setState(() { setState(() {
currentPage += 1; currentPage += 1;

View File

@ -1,14 +1,17 @@
import 'package:cims_apps/application/component/button/back_button_view.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/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/application/theme/color_palette.dart';
import 'package:cims_apps/core/route/route.dart'; import 'package:cims_apps/core/route/route.dart';
import 'package:cims_apps/core/utils/size_config.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/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:cims_apps/features/auth/registration/view/submission_data/terms_and_condition/terms_and_condition_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ResultsView extends StatelessWidget { class ResultsView extends StatelessWidget {
final String totalScore; final int totalScore;
final RiskProfileResult typeResult; final RiskProfileResult typeResult;
const ResultsView( const ResultsView(
{super.key, required this.typeResult, required this.totalScore}); {super.key, required this.typeResult, required this.totalScore});
@ -37,115 +40,15 @@ class ResultsView extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ClipRRect( RiskProfile(totalScore: totalScore, rowSuitableProduct: false),
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(),
),
const SizedBox( const SizedBox(
height: 32, height: 32,
), ),
ButtonView( ButtonView(
name: 'Re-test', name: 'Re-test',
onPressed: () {}, onPressed: () {
routePush(context, page: QuestionView(), routeType: RouteType.pushReplace);
},
marginVertical: 0, marginVertical: 0,
backgroundColor: ColorPalette.white, backgroundColor: ColorPalette.white,
textColor: ColorPalette.primary, textColor: ColorPalette.primary,

View File

@ -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/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/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/plan/view/plan_view.dart';
import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/portfolio_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:cims_apps/features/transaction/view/transaction_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class BottomNavigationItem {
String icon, label;
BottomNavigationItem(this.icon, this.label);
}
class BottomNavigationView extends StatefulWidget { class BottomNavigationView extends StatefulWidget {
const BottomNavigationView({Key? key}) : super(key: key); const BottomNavigationView({Key? key}) : super(key: key);
@ -26,32 +34,20 @@ class _BottomNavigationViewState extends State<BottomNavigationView> {
ProfileView(), ProfileView(),
]; ];
List<BottomNavigationBarItem> listNavigation = const [ List<BottomNavigationItem> listNavigation = [
BottomNavigationBarItem( BottomNavigationItem(PathAssets.iconNavigationHome, 'Home'),
icon: Icon(Icons.home_outlined), BottomNavigationItem(PathAssets.iconNavigationPlan, 'Plan'),
label: 'Home', BottomNavigationItem(PathAssets.iconNavigationTransaction, 'Transaction'),
), BottomNavigationItem(PathAssets.iconNavigationPortfolio, 'Portfolio'),
BottomNavigationBarItem( BottomNavigationItem(PathAssets.iconNavigationProfile, 'Profile')
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',
),
]; ];
return Scaffold( return Scaffold(
body: listWidget[_selectedIndex], body: listWidget[_selectedIndex],
bottomNavigationBar: Padding( bottomNavigationBar: Container(
decoration: const BoxDecoration(
border: Border(top: BorderSide(color: ColorPalette.slate200))
),
padding: const EdgeInsets.symmetric(vertical: 12), padding: const EdgeInsets.symmetric(vertical: 12),
child: BottomNavigationBar( child: BottomNavigationBar(
elevation: 0, elevation: 0,
@ -61,13 +57,25 @@ class _BottomNavigationViewState extends State<BottomNavigationView> {
}); });
}, },
currentIndex: _selectedIndex, 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, type: BottomNavigationBarType.fixed,
showUnselectedLabels: true, showUnselectedLabels: true,
selectedItemColor: ColorPalette.primary, selectedItemColor: ColorPalette.primary,
unselectedItemColor: Colors.black, unselectedItemColor: Colors.black,
selectedLabelStyle: const TextStyle(color: ColorPalette.primary), selectedLabelStyle: const TextStyle(color: ColorPalette.primary, fontSize: 12),
unselectedLabelStyle: const TextStyle(color: Colors.black), unselectedLabelStyle: const TextStyle(color: Colors.black, fontSize: 12),
), ),
), ),
); );

View File

@ -102,7 +102,7 @@ class _InvestTypeViewState extends State<InvestTypeView> {
onTap: () { onTap: () {
provider.setSelectedProduct(e.value); provider.setSelectedProduct(e.value);
routePush(context, routePush(context,
page: ProductView(widget.title)); page: ProductView(selectedProduct: e.value));
}, },
child: Padding( child: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(

View File

@ -40,42 +40,50 @@ class _PlanViewState extends State<PlanView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return ChangeNotifierProvider(
appBar: CustomAppBar(height: 70, title: 'Investment Plan'), create: (context) => PlanViewModel(),
body: SingleChildScrollView( child: Scaffold(
padding: EdgeInsets.all(24), appBar: CustomAppBar(
child: Column( height: SizeConfig.height * 0.08,
crossAxisAlignment: CrossAxisAlignment.start, title: 'Investment Plan',
children: [ leading: SizedBox(),
RiskProfile( ),
totalScore: 26, body: SingleChildScrollView(
rowSuitableProduct: true padding: EdgeInsets.all(24),
), child: Column(
SizedBox( crossAxisAlignment: CrossAxisAlignment.start,
height: 32, children: [
), RiskProfile(
Text('Your Goal in Investing', totalScore: 26,
style: TextStyle( rowSuitableProduct: true
fontWeight: FontWeight.w700,
color: ColorPalette.slate800,
fontSize: 18
), ),
), SizedBox(
SizedBox( height: 32,
height: 24, ),
), Text('Your Goal in Investing',
GoalInvestingView( style: TextStyle(
onListSelected: (p0) { fontWeight: FontWeight.w700,
showModalBottomSheet( color: ColorPalette.slate800,
context: context, fontSize: 18
isScrollControlled: true, ),
builder: (context) { ),
return modalInvest(context, p0); SizedBox(
}, height: 24,
); ),
}, GoalInvestingView(
) onListSelected: (p0) {
], print(p0);
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return modalInvest(context, p0);
},
);
},
)
],
),
), ),
), ),
); );

View File

@ -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/image/image_view.dart';
import 'package:cims_apps/application/component/subscribe/total_payment_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/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/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:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ResultOptionsProduct extends StatelessWidget { class ResultOptionsProduct extends StatelessWidget {
final int totalInvest; final int totalInvest;
@ -19,134 +24,169 @@ class ResultOptionsProduct extends StatelessWidget {
Product(name: 'Gemilang Kas 2 Kelas A', type: 'Shares', totalPercent: 0.1) Product(name: 'Gemilang Kas 2 Kelas A', type: 'Shares', totalPercent: 0.1)
]; ];
return Container( return ChangeNotifierProvider(
decoration: BoxDecoration( create: (context) => PlanViewModel(),
color: Colors.white, child: Consumer<PlanViewModel>(
borderRadius: BorderRadius.circular(16) builder: (context, provider, child) {
), return Container(
padding: const EdgeInsets.all(24), decoration: BoxDecoration(
child: Column( color: Colors.white,
mainAxisSize: MainAxisSize.min, borderRadius: BorderRadius.circular(16)
children: [ ),
const Row( padding: const EdgeInsets.all(24),
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(
child: Column( child: Column(
children: listProduct.asMap().entries.map((e) { mainAxisSize: MainAxisSize.min,
return Container( children: [
margin: const EdgeInsets.only(bottom: 16), Row(
padding: const EdgeInsets.all(16), mainAxisAlignment: MainAxisAlignment.spaceBetween,
decoration: BoxDecoration( children: [
color: Colors.white, GestureDetector(
border: Border.all(color: ColorPalette.slate200), onTap: () {
borderRadius: BorderRadius.circular(12), Navigator.pop(context);
boxShadow: const [ showModalBottomSheet(
BoxShadow( context: context,
color: Color(0XFF1E293B0A) 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( child: Column(
children: [ children: listProduct.asMap().entries.map((e) {
Row( return Container(
children: [ margin: const EdgeInsets.only(bottom: 16),
const ImageView(image: PathAssets.iconGoogle, width: 30,), padding: const EdgeInsets.all(16),
const SizedBox( decoration: BoxDecoration(
width: 12, color: Colors.white,
), border: Border.all(color: ColorPalette.slate200),
Expanded( borderRadius: BorderRadius.circular(12),
child: Column( boxShadow: const [
crossAxisAlignment: CrossAxisAlignment.start, BoxShadow(
color: Color(0XFF1E293B0A)
)
]
),
child: Column(
children: [
Row(
children: [ children: [
Text(e.value.name ?? '', const ImageView(image: PathAssets.iconGoogle, width: 30,),
style: const TextStyle( const SizedBox(
fontWeight: FontWeight.w700, width: 12,
color: ColorPalette.slate800, ),
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,), Text('${(e.value.totalPercent! * 100).toInt()} %',
Container( style: const TextStyle(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), fontWeight: FontWeight.w700,
decoration: BoxDecoration( fontSize: 16,
border: Border.all(color: ColorPalette.investTypeColor[e.value.type]!), color: ColorPalette.slate800
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 Padding(
Text('${(e.value.totalPercent! * 100).toInt()} %', padding: EdgeInsets.symmetric(vertical: 16),
style: const TextStyle( child: Divider(height: 1, color: ColorPalette.slate200),
fontWeight: FontWeight.w700,
fontSize: 16,
color: ColorPalette.slate800
), ),
) GestureDetector(
], onTap: () {
), routePush(context, page: ProductView(selectedProduct: e.value, seeMore: true));
const Padding( },
padding: EdgeInsets.symmetric(vertical: 16), child: const Text('See More',
child: Divider(height: 1, color: ColorPalette.slate200), style: TextStyle(
), color: ColorPalette.slate500,
GestureDetector( fontWeight: FontWeight.w600,
onTap: () { ),
}, ),
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<PlanViewModel>(
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,
)
],
), ),
); );
} }

View File

@ -3,4 +3,10 @@ import 'package:flutter/material.dart';
class PlanViewModel extends ChangeNotifier { class PlanViewModel extends ChangeNotifier {
List<Product> listProduct = []; List<Product> listProduct = [];
bool isAgree = false;
void setAgree() {
isAgree = !isAgree;
notifyListeners();
}
} }

View File

@ -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<PortfolioProduct> 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,
),
)
],
);
}
}

View File

@ -1,7 +1,10 @@
import 'package:cims_apps/application/assets/path_assets.dart'; 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/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/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/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:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -147,9 +150,31 @@ class _PortofolioViewState extends State<PortofolioView> {
), ),
menuPortofolio(), menuPortofolio(),
const SizedBox( 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<PortofolioView> {
seePortofolioValue seePortofolioValue
? Icons.visibility_off_outlined ? Icons.visibility_off_outlined
: Icons.visibility_outlined, : Icons.visibility_outlined,
size: 18,
color: const Color(0xff93C5FD))) color: const Color(0xff93C5FD)))
], ],
), ),
@ -358,4 +384,85 @@ class _PortofolioViewState extends State<PortofolioView> {
); );
}).toList(); }).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)
],
)
],
)
],
),
),
);
}
} }

View File

@ -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<ChangeAmount> createState() => _ChangeAmountState();
}
class _ChangeAmountState extends State<ChangeAmount> {
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<RedeemProductViewModel>(
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
),
),
)
],
),
)
],
),
);
}
}

View File

@ -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<Account> listAccount = [
Account('Muhamad Rosyidin', 'BRI', '902139012324'),
Account('Achmad Muhaimin', 'BCA', '21391283928')
];
return ChangeNotifierProvider(
create: (context) => RedeemProductViewModel(),
child: Consumer<RedeemProductViewModel>(
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<String> 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),
),
),
)
],
),
);
}
}

View File

@ -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<RedeemProduct> createState() => _RedeemProductState();
}
class _RedeemProductState extends State<RedeemProduct> {
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<RedeemProductViewModel>(
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<RedeemProductViewModel>(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<String> 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
),
)
],
),
),
)
],
),
)
],
);
}
}

View File

@ -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<RedeemProductViewModel>(
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
),
)
],
),
],
),
)
],
),
);
}
}

View File

@ -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();
}
}

View File

@ -24,8 +24,9 @@ class Time {
} }
class ProductView extends StatefulWidget { class ProductView extends StatefulWidget {
final String investType; final bool seeMore;
const ProductView(this.investType, {super.key}); final Product selectedProduct;
const ProductView({super.key, required this.selectedProduct, this.seeMore = false});
@override @override
State<ProductView> createState() => _ProductViewState(); State<ProductView> createState() => _ProductViewState();
@ -144,22 +145,23 @@ class _ProductViewState extends State<ProductView> {
], ],
), ),
), ),
bottomNavigationBar: Container( bottomNavigationBar: !widget.seeMore ?
height: SizeConfig.height * .1, Container(
padding: const EdgeInsets.symmetric(horizontal: 24), height: SizeConfig.height * .1,
child: ButtonView( padding: const EdgeInsets.symmetric(horizontal: 24),
name: 'Subscribe', child: ButtonView(
onPressed: () { name: 'Subscribe',
showModalBottomSheet( onPressed: () {
context: context, showModalBottomSheet(
isScrollControlled: true, context: context,
builder: (context) => SelectGoalInvesting(), isScrollControlled: true,
); builder: (context) => SelectGoalInvesting(),
}, );
height: SizeConfig.height * 0.06, },
marginVertical: 16, height: SizeConfig.height * 0.06,
), marginVertical: 16,
), ),
) : SizedBox(),
), ),
); );
} }
@ -177,7 +179,7 @@ class _ProductViewState extends State<ProductView> {
SizedBox(width: 8), SizedBox(width: 8),
Expanded( Expanded(
child: Text( child: Text(
'Gemilang Dana Kas Maxima', widget.selectedProduct.name ?? '',
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
@ -190,17 +192,18 @@ class _ProductViewState extends State<ProductView> {
], ],
), ),
), ),
SizedBox(width: 12),
Container( Container(
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(6),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40), borderRadius: BorderRadius.circular(40),
color: ColorPalette.investTypeBgColor[widget.investType] ?? Colors.white, color: ColorPalette.investTypeBgColor[widget.selectedProduct.type] ?? Colors.white,
border: Border.all(width: 2, color: ColorPalette.investTypeColor[widget.investType] ?? Colors.white) border: Border.all(width: 2, color: ColorPalette.investTypeColor[widget.selectedProduct.type] ?? Colors.white)
), ),
child: Text( child: Text(
widget.investType, widget.selectedProduct.type ?? '',
style: TextStyle( style: TextStyle(
color: ColorPalette.investTypeColor[widget.investType], color: ColorPalette.investTypeColor[widget.selectedProduct.type],
fontWeight: FontWeight.w600 fontWeight: FontWeight.w600
), ),
), ),

View File

@ -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/input_investment_view.dart';
import 'package:cims_apps/application/component/subscribe/total_payment_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/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:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -11,10 +12,9 @@ class SelectGoalInvesting extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiProvider(
providers: [ return ChangeNotifierProvider(
ChangeNotifierProvider(create: (context) => ProductViewModel(),) create: (context) => ProductViewModel(),
],
child: Consumer<ProductViewModel>( child: Consumer<ProductViewModel>(
builder: (context, provider, child) { builder: (context, provider, child) {
return Container( return Container(
@ -51,23 +51,39 @@ class SelectGoalInvesting extends StatelessWidget {
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: (context) { builder: (context) {
return InputInvestmentView( return ChangeNotifierProvider(
selectedPlan: p0, create: (context) => ProductViewModel(),
nextMove: (value) { child: Consumer<ProductViewModel>(
Navigator.pop(context); builder: (context, provider, child) {
int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll(',', '')); return InputInvestmentView(
showModalBottomSheet( selectedPlan: p0,
context: context, nextMove: (value) {
isScrollControlled: true, Navigator.pop(context);
builder: (context) => int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll(',', ''));
TotalPaymentView( showModalBottomSheet(
listProduct: [ context: context,
provider.getSelectedProduct isScrollControlled: true,
], builder: (context) =>
totalInvest: formatIntParse, ChangeNotifierProvider(
) create: (context) => ProductViewModel(),
); child: Consumer<ProductViewModel>(
}, builder: (context, provider, child) {
return TotalPaymentView(
listProduct: [
provider.getSelectedProduct
],
totalInvest: formatIntParse,
isAgree: provider.isAgree,
onTapAgree: provider.setAgree,
);
}
),
)
);
},
);
}
),
); );
}, },
); );

View File

@ -14,6 +14,7 @@ class ProductViewModel extends ChangeNotifier {
Product get getSelectedProduct => selectedProduct; Product get getSelectedProduct => selectedProduct;
double totalInvestment = 0; double totalInvestment = 0;
bool isAgree = false;
void setSelectedProduct(Product product) { void setSelectedProduct(Product product) {
selectedProduct = product; selectedProduct = product;
@ -24,4 +25,9 @@ class ProductViewModel extends ChangeNotifier {
totalInvestment = value; totalInvestment = value;
notifyListeners(); notifyListeners();
} }
void setAgree() {
isAgree = !isAgree;
notifyListeners();
}
} }

View File

@ -8,7 +8,7 @@ class ProfileView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar(height: SizeConfig.height * .1, title: 'Profile'), appBar: CustomAppBar(height: SizeConfig.height * .08, title: 'Profile'),
); );
} }
} }

View File

@ -8,8 +8,7 @@ class TransactionView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: appBar: CustomAppBar(height: SizeConfig.height * 0.08, title: 'Transaction'),
CustomAppBar(height: SizeConfig.height * .1, title: 'Transaction'),
); );
} }
} }