feat: flow subscribe product

This commit is contained in:
Prajna Prayoga 2024-02-19 19:58:29 +07:00
parent 0762a8ab0c
commit 99db140a0c
31 changed files with 1170 additions and 372 deletions

BIN
assets/icons/icon-bag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
assets/icons/icon-car.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
assets/icons/icon-cart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/icons/icon-plane.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@ -39,6 +39,13 @@ class PathAssets {
static const String iconCreatePlan = 'assets/icons/icon-create-plan.png';
static const String iconThumb = 'assets/icons/icon-thumb.png';
static const String iconPortofolio = 'assets/icons/icon-portofolio.png';
static const String iconPlane = 'assets/icons/icon-plane.png';
static const String iconCart = 'assets/icons/icon-cart.png';
static const String iconBag = 'assets/icons/icon-bag.png';
static const String iconMarket = 'assets/icons/icon-market.png';
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';
/// IMAGE
static const String imgSplashLogo = 'assets/images/splash-logo.png';
@ -72,4 +79,6 @@ class PathAssets {
static const String imgGuideBank = 'assets/images/img-guide-bank.png';
static const String imgGuide1 = 'assets/images/img-guide1.png';
static const String imgGuide2 = 'assets/images/img-guide2.png';
static const String imgOpenShopping = 'assets/images/img-open-shopping.png';
static const String imgPaymentSuccess = 'assets/images/img-payment-success.png';
}

View File

@ -0,0 +1,41 @@
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:flutter/material.dart';
class TypeApp {
String img, title;
TypeApp(this.img, this.title);
}
class ModalRedirectApp extends StatelessWidget {
final String value;
const ModalRedirectApp({super.key, required this.value});
@override
Widget build(BuildContext context) {
Map<String, TypeApp> typeApp = {
'Shopping Pay': TypeApp(PathAssets.imgOpenShopping, 'Shopping App'),
};
return Column(
children: [
ImageView(image: typeApp[value]!.img),
Text('Open ${typeApp[value]!.title}',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w600,
color: ColorPalette.slate800
),
),
Text('You will be redirected to the ${typeApp[value]!.title.toLowerCase()} to continue the payment',
style: TextStyle(
fontSize: 16,
color: ColorPalette.slate400
),
)
],
);
}
}

View File

@ -1,5 +1,7 @@
import 'package:cims_apps/application/assets/path_assets.dart';
import 'package:cims_apps/application/component/subscribe/other_plan_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:flutter/material.dart';
@ -20,7 +22,7 @@ class GoalInvestingView extends StatelessWidget {
GoalInvest(PathAssets.iconToga, 'Education'),
GoalInvest(PathAssets.iconCake, 'Marriage'),
GoalInvest(PathAssets.iconHouse, 'Old age days'),
GoalInvest(PathAssets.iconCreatePlan, 'Create Plan'),
GoalInvest(PathAssets.iconCreatePlan, 'Other Plan'),
];
return Column(
@ -30,7 +32,18 @@ class GoalInvestingView extends StatelessWidget {
padding: EdgeInsets.only(top: e.key != 0 ? 16 : 0),
child: ListTile(
onTap: () {
onListSelected(e.value.title);
if(e.value.title == 'Other Plan'){
routePush(
context,
page: OtherPlanView(
selectedPlan: (value) {
onListSelected(e.value.title);
},
)
);
}else{
onListSelected(e.value.title);
}
},
shape: RoundedRectangleBorder(
side: BorderSide(color: ColorPalette.slate200),
@ -51,10 +64,11 @@ class GoalInvestingView extends StatelessWidget {
title: Text(e.value.title,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16
fontSize: 16,
color: ColorPalette.slate800
),
),
trailing: Icon(Icons.chevron_right_rounded),
trailing: Icon(Icons.chevron_right_rounded, color: ColorPalette.slate400),
),
);
}).toList()

View File

@ -0,0 +1,143 @@
import 'package:cims_apps/application/component/button/button_view.dart';
import 'package:cims_apps/application/component/numeric_pad/numeric_pad.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:flutter/material.dart';
class InputInvestmentView extends StatefulWidget {
final String selectedPlan;
final void Function(String value) nextMove;
const InputInvestmentView({super.key, required this.selectedPlan, required this.nextMove});
@override
State<InputInvestmentView> createState() => _InputInvestmentViewState();
}
class _InputInvestmentViewState extends State<InputInvestmentView> {
TextEditingController inputController = TextEditingController();
@override
void initState() {
// TODO: implement initState
inputController.text = 'Rp 0';
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
inputController.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16)
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 16),
Padding(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(widget.selectedPlan,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
),
),
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
),
)
],
)
],
),
TextField(
controller: inputController,
textAlign: TextAlign.center,
style: 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){
inputController.text = NumberFormatter.numberCurrency(parseValue, 'Rp ', 'id_ID', decimalDigits: 0);
}else{
inputController.text = NumberFormatter.numberCurrency(0, 'Rp ', 'id_ID', decimalDigits: 0);
}
},
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: ColorPalette.primary,
width: 2
),
)
),
),
SizedBox(height: 12),
Text('Minimum Budget Rp1,000,000',
style: TextStyle(
color: ColorPalette.slate400,
fontSize: 16,
fontWeight: FontWeight.w600
),
),
SizedBox(height: 16),
NumericPad(onNumberSelected: (p0) {
String checkIsZeroInput = inputController.text.replaceAll('Rp ', '').replaceAll(',', '');
String getNumeric = p0;
if(p0.isNotEmpty){
if(checkIsZeroInput != '0'){
getNumeric = checkIsZeroInput + getNumeric;
}
}else{
getNumeric = checkIsZeroInput.substring(0, checkIsZeroInput.length - 1);
}
String formatNumeric = NumberFormatter.numberCurrency(
double.parse(getNumeric), 'Rp ', 'id_ID', decimalDigits: 0).replaceAll('.', ',');
inputController.text = formatNumeric;
}),
SizedBox(height: 8),
ButtonView(
name: 'Next',
onPressed: () {
widget.nextMove(inputController.text);
},
width: SizeConfig.width,
heightWrapContent: true,
contentPadding: EdgeInsets.symmetric(vertical: 16),
marginVertical: 0,
)
],
),
),
],
),
);;
}
}

View File

@ -0,0 +1,182 @@
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';
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/theme/color_palette.dart';
import 'package:cims_apps/core/utils/size_config.dart';
import 'package:flutter/material.dart';
class Plan {
String img, name;
Plan(this.img, this.name);
}
class OtherPlanView extends StatefulWidget {
final void Function(String value) selectedPlan;
const OtherPlanView({super.key, required this.selectedPlan});
@override
State<OtherPlanView> createState() => _OtherPlanViewState();
}
class _OtherPlanViewState extends State<OtherPlanView> {
TextEditingController createController = TextEditingController();
Plan selectedPlan = Plan('', '');
List<Plan> listPlan = [
Plan(PathAssets.iconToga, 'Education'),
Plan(PathAssets.iconCake, 'Marriage'),
Plan(PathAssets.iconHouse, 'Home'),
Plan(PathAssets.iconTicket, 'Entertainment'),
Plan(PathAssets.iconGadget, 'Gadget'),
Plan(PathAssets.iconMarket, 'Business'),
Plan(PathAssets.iconBag, 'Fashion'),
Plan(PathAssets.iconCart, 'Shop'),
Plan(PathAssets.iconCar, 'Vehicle'),
Plan(PathAssets.iconPlane, 'Holiday'),
Plan(PathAssets.iconCreatePlan, 'Create Plan'),
];
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
createController.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
height: 70,
title: 'Other Plan'
),
body: GridView(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 32),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
children: listPlan.map((e) => cardPlan(e)).toList(),
),
bottomNavigationBar: Container(
height: 110,
padding: EdgeInsets.symmetric(horizontal: 24),
child: ButtonView(
name: 'Select',
disabled: !(selectedPlan.img != ''),
onPressed: () {
Navigator.pop(context);
widget.selectedPlan(selectedPlan.name);
},
heightWrapContent: true,
width: SizeConfig.width,
contentPadding: EdgeInsets.symmetric(vertical: 12),
textColor: selectedPlan.img == '' ? ColorPalette.slate500 : ColorPalette.white,
disabledBgColor: ColorPalette.slate200,
backgroundColor: ColorPalette.primary,
),
),
);
}
Widget cardPlan(Plan plan) {
return GestureDetector(
onTap: () {
if(plan.name == 'Create Plan'){
showModalBottomSheet(
context: context,
builder: (context) => modalCreatePlan(),
);
}
setState(() {
selectedPlan = plan;
});
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
border: Border.all(color: selectedPlan == plan ? ColorPalette.primary : Colors.transparent)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: SizeConfig.width * 0.12,
height: SizeConfig.width * 0.12,
padding: EdgeInsets.all(12),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: ColorPalette.blue200.withOpacity(0.5)
),
child: ImageView(image: plan.img)
),
SizedBox(height: 12),
Text(plan.name,
style: TextStyle(
color: selectedPlan == plan ? ColorPalette.primary : ColorPalette.slate800,
fontWeight: FontWeight.w600
),
)
],
),
),
);
}
Widget modalCreatePlan() {
return Container(
padding: EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Create your plan',
style: TextStyle(
fontWeight: FontWeight.w600,
color: ColorPalette.slate800,
fontSize: 16
),
),
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.close_rounded),
)
],
),
TextFormView(
name: 'Objective Name',
ctrl: createController,
),
SizedBox(height: 24),
ButtonView(
name: 'Select',
marginVertical: 0,
disabled: !(createController.text != ''),
onPressed: () {
Navigator.of(context)..pop()..pop();
widget.selectedPlan(selectedPlan.name);
},
heightWrapContent: true,
width: SizeConfig.width,
contentPadding: EdgeInsets.symmetric(vertical: 16),
textColor: createController.text == '' ? ColorPalette.slate500 : ColorPalette.white,
disabledBgColor: ColorPalette.slate200,
backgroundColor: ColorPalette.primary,
),
],
),
);
}
}

View File

@ -1,21 +1,33 @@
import 'package:cims_apps/application/component/button/button_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/number_formatter.dart';
import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view/step_invest_plan/result_options_product.dart';
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view/step_subscribe/payment_method_view.dart';
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart';
import 'package:flutter/material.dart';
class ResultTotalProduct extends StatelessWidget {
class TotalPaymentView extends StatefulWidget {
final int totalInvest;
final List<Product> listProduct;
const ResultTotalProduct({super.key, required this.listProduct, required this.totalInvest});
const TotalPaymentView({
super.key,
required this.listProduct,
required this.totalInvest,
});
@override
State<TotalPaymentView> createState() => _TotalPaymentViewState();
}
class _TotalPaymentViewState extends State<TotalPaymentView> {
bool isAgreement = false;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16)
color: Colors.white,
borderRadius: BorderRadius.circular(16)
),
child: Column(
mainAxisSize: MainAxisSize.min,
@ -25,7 +37,7 @@ class ResultTotalProduct extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Your Investment Today',
const Text('Your Investment Today',
style: TextStyle(
color: ColorPalette.slate800,
fontWeight: FontWeight.w600,
@ -33,92 +45,92 @@ class ResultTotalProduct extends StatelessWidget {
),
),
GestureDetector(
onTap: () => Navigator.pop(context),
child: Icon(Icons.close_rounded)
onTap: () => Navigator.pop(context),
child: const Icon(Icons.close_rounded)
)
],
),
),
...listProduct.asMap().entries.map((e) {
...widget.listProduct.asMap().entries.map((e) {
return Container(
padding: EdgeInsets.only(left: 16, right: 24, bottom: 16, top: 16),
padding: const EdgeInsets.only(left: 16, right: 24, bottom: 16, top: 16),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
color: ColorPalette.investTypeColor[e.value.type]!,
width: 8,
border: Border(
left: BorderSide(
width: 8,
color: ColorPalette.investTypeColor[e.value.type]!
)
)
)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 5,
child: Text(e.value.name,
style: TextStyle(
color: ColorPalette.slate400,
fontWeight: FontWeight.w600,
fontSize: 16
),
)
flex: 5,
child: Text(e.value.name ?? '',
style: const TextStyle(
color: ColorPalette.slate400,
fontWeight: FontWeight.w600,
fontSize: 16
),
)
),
Expanded(
flex: 7,
child: Text(
NumberFormatter.numberCurrency(totalInvest / e.value.totalPercent, 'Rp ', 'id_ID'),
textAlign: TextAlign.end,
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 18,
color: ColorPalette.slate800
),
)
flex: 7,
child: Text(
NumberFormatter.numberCurrency(widget.totalInvest * e.value.totalPercent!, 'Rp ', 'id_ID'),
textAlign: TextAlign.end,
style: const TextStyle(
fontWeight: FontWeight.w700,
fontSize: 18,
color: ColorPalette.slate800
),
)
)
],
),
);
}).toList(),
SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
const SizedBox(height: 16),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Purchase Commission',
style: TextStyle(
color: ColorPalette.slate400,
fontWeight: FontWeight.w600,
fontSize: 16
),
),
Text('Free',
style: TextStyle(
color: ColorPalette.primary,
fontSize: 18,
fontWeight: FontWeight.w700
),
)
],
),
),
SizedBox(height: 16,),
Container(
color: ColorPalette.slate200.withOpacity(0.5),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total',
style: TextStyle(
color: ColorPalette.slate400,
fontWeight: FontWeight.w600,
fontSize: 16
),
),
Text(NumberFormatter.numberCurrency(totalInvest, 'Rp ', 'id_ID'),
textAlign: TextAlign.end,
Text('Free',
style: TextStyle(
color: ColorPalette.primary,
fontSize: 18,
fontWeight: FontWeight.w700
),
)
],
),
),
const SizedBox(height: 16,),
Container(
color: ColorPalette.slate200.withOpacity(0.5),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('Total',
style: TextStyle(
color: ColorPalette.slate400,
fontWeight: FontWeight.w600,
fontSize: 16
),
),
Text(NumberFormatter.numberCurrency(widget.totalInvest, 'Rp ', 'id_ID'),
textAlign: TextAlign.end,
style: const TextStyle(
fontWeight: FontWeight.w700,
fontSize: 18,
color: ColorPalette.slate800
@ -133,16 +145,16 @@ class ResultTotalProduct extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Payment',
const Text('Total Payment',
style: TextStyle(
color: ColorPalette.slate400,
fontWeight: FontWeight.w600,
fontSize: 16
),
),
Text(NumberFormatter.numberCurrency(totalInvest, 'Rp ', 'id_ID'),
Text(NumberFormatter.numberCurrency(widget.totalInvest, 'Rp ', 'id_ID'),
textAlign: TextAlign.end,
style: TextStyle(
style: const TextStyle(
fontWeight: FontWeight.w700,
fontSize: 18,
color: ColorPalette.slate800
@ -152,13 +164,15 @@ class ResultTotalProduct extends StatelessWidget {
),
),
ButtonView(
disabled: true,
disabled: !isAgreement,
name: 'Subscribe Now',
onPressed: () {
routePush(context, page: PaymentMethodView(
totalInvest: widget.totalInvest,
));
},
disabledBgColor: ColorPalette.slate200.withOpacity(0.5),
textColor: ColorPalette.slate400,
textColor: isAgreement ? Colors.white : ColorPalette.slate400,
textWeight: FontWeight.w700,
textSize: 20,
backgroundColor: ColorPalette.primary,
@ -169,29 +183,48 @@ class ResultTotalProduct extends StatelessWidget {
}
Widget buttonAgreement() {
bool isAgree = isAgreement;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 24,
width: 24,
child: Radio(
value: false,
groupValue: false,
onChanged: (value) {
},
activeColor: ColorPalette.primary,
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
),
),
),
),
),
SizedBox(width: 12,),
const SizedBox(width: 12,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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.',
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,
@ -202,7 +235,7 @@ class ResultTotalProduct extends StatelessWidget {
onTap: () {
},
child: Text('Read More',
child: const Text('Read More',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,

View File

@ -0,0 +1,52 @@
import 'package:cims_apps/application/component/button/button_view.dart';
import 'package:cims_apps/application/component/image/image_view.dart';
import 'package:cims_apps/core/utils/size_config.dart';
import 'package:flutter/material.dart';
class SuccessView extends StatelessWidget {
final String img;
final String textTitle;
final Widget? subtitle;
final void Function() nextRoute;
const SuccessView({super.key,
required this.img,
required this.textTitle,
required this.subtitle,
required this.nextRoute
});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ImageView(image: img, width: SizeConfig.width * .8,),
Text(textTitle,
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 28,
),
),
subtitle ?? SizedBox()
],
),
),
bottomNavigationBar: Container(
padding: EdgeInsets.all(24),
height: 110,
width: SizeConfig.width,
child: ButtonView(
name: 'Done',
onPressed: nextRoute,
marginVertical: 0,
heightWrapContent: true,
width: SizeConfig.width,
textSize: 20,
contentPadding: EdgeInsets.symmetric(vertical: 12),
),
),
);
}
}

View File

@ -5,6 +5,7 @@ import 'package:remove_emoji_input_formatter/remove_emoji_input_formatter.dart';
class TextFormView extends StatelessWidget {
final String name;
final double nameSize;
final String? helperText;
final String? initialValue;
final VoidCallback? onTap;
@ -40,6 +41,7 @@ class TextFormView extends StatelessWidget {
TextFormView(
{Key? key,
required this.name,
this.nameSize = 16,
this.helperText,
this.onTap,
this.fontColorDisabled,
@ -97,17 +99,17 @@ class TextFormView extends StatelessWidget {
children: [
Text(
name,
style: const TextStyle(
fontSize: 16,
style: TextStyle(
fontSize: nameSize,
fontWeight: FontWeight.w600,
color: ColorPalette.slate800,
),
),
suffixLable ??
const Text(
Text(
"",
style: TextStyle(
fontSize: 16,
fontSize: nameSize,
color: Colors.red,
),
),

View File

@ -75,6 +75,7 @@ class ColorPalette {
static const Color backgroundBlueLight = Color(0xFFEBF3FD);
static const Color blue50 = Color(0xFFEFF6FF);
static const Color blue200 = Color(0xFFBFDBFE);
static const Color blue900 = Color(0xFF1E3A8A);
static const Color slate50 = Color(0xFFF8FAFC);
static const Color slate200 = Color(0xFFE2E8F0);
static const Color slate300 = Color(0xFFCBD5E1);

View File

@ -65,6 +65,7 @@ class PasswordView extends StatelessWidget {
name: 'Confirm',
heightWrapContent: true,
width: SizeConfig.width,
textSize: 18,
marginVertical: 0,
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
onPressed: nextStep,

View File

@ -50,28 +50,25 @@ class _BottomNavigationViewState extends State<BottomNavigationView> {
),
];
return ChangeNotifierProvider(
create: (context) => PlanViewModel(),
child: Scaffold(
body: listWidget[_selectedIndex],
bottomNavigationBar: Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: BottomNavigationBar(
elevation: 0,
onTap: (value) {
setState(() {
_selectedIndex = value;
});
},
currentIndex: _selectedIndex,
items: listNavigation,
type: BottomNavigationBarType.fixed,
showUnselectedLabels: true,
selectedItemColor: ColorPalette.primary,
unselectedItemColor: Colors.black,
selectedLabelStyle: const TextStyle(color: ColorPalette.primary),
unselectedLabelStyle: const TextStyle(color: Colors.black),
),
return Scaffold(
body: listWidget[_selectedIndex],
bottomNavigationBar: Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: BottomNavigationBar(
elevation: 0,
onTap: (value) {
setState(() {
_selectedIndex = value;
});
},
currentIndex: _selectedIndex,
items: listNavigation,
type: BottomNavigationBarType.fixed,
showUnselectedLabels: true,
selectedItemColor: ColorPalette.primary,
unselectedItemColor: Colors.black,
selectedLabelStyle: const TextStyle(color: ColorPalette.primary),
unselectedLabelStyle: const TextStyle(color: Colors.black),
),
),
);

View File

@ -228,7 +228,7 @@ class _HomeViewState extends State<HomeView> {
children: listPortofolioType.asMap().entries.map((e) {
return GestureDetector(
onTap: () {
routePush(context, page: InvestTypeView(e.value.name));
routePush(context, page: InvestTypeView(title: e.value.name));
},
child: Container(
color: Colors.white,

View File

@ -6,21 +6,14 @@ 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';
import 'package:cims_apps/core/utils/size_config.dart';
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/product_view.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';
class Product {
String name;
double yield;
double priceUnit;
double funds;
Product(this.name, this.yield, this.priceUnit, this.funds);
}
import 'package:provider/provider.dart';
class InvestTypeView extends StatefulWidget {
final String title;
const InvestTypeView(this.title, {super.key});
const InvestTypeView({super.key, required this.title});
@override
State<InvestTypeView> createState() => _InvestTypeViewState();
@ -29,71 +22,89 @@ class InvestTypeView extends StatefulWidget {
class _InvestTypeViewState extends State<InvestTypeView> {
List<Product> listProduct = [
Product('Gemilang Dana Kas Maxima', 8.17, 2600.79, 6300000),
Product('Gemilang Dana Likuid', 6.42, 1600.79, 2340000),
Product('Gemilang Income Fund', 8.17, 2600.79, 6300000)
Product(name: 'Gemilang Dana Kas Maxima', type: '', yield: 8.17, priceUnit: 2600.79, funds: 6300000),
Product(name: 'Gemilang Dana Likuid', type: '', yield: 6.42, priceUnit: 1600.79, funds: 2340000),
Product(name: 'Gemilang Income Fund', type: '', yield: 8.17, priceUnit: 2600.79, funds: 6300000)
];
@override
void initState() {
// TODO: implement initState
super.initState();
listProduct = listProduct.map((e) {
e.type = widget.title;
return e;
}).toList();
}
@override
Widget build(BuildContext context) {
return Scaffold(
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,
return ChangeNotifierProvider<ProductViewModel>(
create: (context) => ProductViewModel(),
child: Consumer<ProductViewModel>(
builder: (context, provider, child) {
return Scaffold(
body: SizedBox(
width: SizeConfig.width,
height: SizeConfig.height,
child: Stack(
children: [
const ImageView(image: PathAssets.imgDashboardAccount),
Column(
children: [
const BackButtonView(),
TextTitle(title: widget.title, color: Colors.white),
SizedBox(
width: SizeConfig.width * 0.1,
)
const SizedBox(
height: 50,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BackButtonView(),
TextTitle(title: widget.title, color: Colors.white),
SizedBox(
width: SizeConfig.width * 0.1,
)
],
),
),
const SizedBox(
height: 24,
),
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white
),
child: Column(
children: [
filters(),
ListView(
shrinkWrap: true,
children: listProduct.asMap().entries.map((e) {
return GestureDetector(
onTap: () {
provider.setSelectedProduct(e.value);
routePush(context, page: ProductView(widget.title));
},
child: Padding(
padding: EdgeInsets.only(top: e.key != 0 ? 24 : 0),
child: cardProduct(e.value),
),
);
}).toList(),
)
],
),
),
],
),
),
const SizedBox(
height: 24,
),
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white
),
child: Column(
children: [
filters(),
ListView(
shrinkWrap: true,
children: listProduct.asMap().entries.map((e) {
return GestureDetector(
onTap: () {
routePush(context, page: ProductView(widget.title));
},
child: Padding(
padding: EdgeInsets.only(top: e.key != 0 ? 24 : 0),
child: cardProduct(e.value),
),
);
}).toList(),
)
],
),
),
],
)
],
),
)
],
),
),
);
}
),
);
}
@ -158,7 +169,7 @@ class _InvestTypeViewState extends State<InvestTypeView> {
),
Expanded(
child: Text(
product.name,
product.name ?? '',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18

View File

@ -1,6 +1,7 @@
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/goal_investing_view.dart';
import 'package:cims_apps/application/component/subscribe/goal_investing_view.dart';
import 'package:cims_apps/application/component/subscribe/input_investment_view.dart';
import 'package:cims_apps/application/component/numeric_pad/numeric_pad.dart';
import 'package:cims_apps/application/component/risk_profile.dart';
import 'package:cims_apps/application/component/text_form/text_form_view.dart';
@ -22,6 +23,13 @@ class PlanView extends StatefulWidget {
class _PlanViewState extends State<PlanView> {
TextEditingController inputController = TextEditingController();
@override
void initState() {
// TODO: implement initState
inputController.text = 'Rp 0';
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
@ -103,101 +111,13 @@ class _PlanViewState extends State<PlanView> {
),
),
Divider(color: ColorPalette.slate200, height: 1),
Padding(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(text,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
),
),
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
),
)
],
)
],
),
TextField(
controller: inputController,
textAlign: TextAlign.center,
style: 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){
inputController.text = NumberFormatter.numberCurrency(parseValue, 'Rp ', 'id_ID', decimalDigits: 0);
}else{
inputController.text = NumberFormatter.numberCurrency(0, 'Rp ', 'id_ID', decimalDigits: 0);
}
},
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: ColorPalette.primary,
width: 2
),
)
),
),
SizedBox(height: 12),
Text('Minimum Budget Rp1,000,000',
style: TextStyle(
color: ColorPalette.slate400,
fontSize: 16,
fontWeight: FontWeight.w600
),
),
SizedBox(height: 16),
NumericPad(onNumberSelected: (p0) {
String checkIsZeroInput = inputController.text.replaceAll('Rp ', '').replaceAll(',', '');
String getNumeric = p0;
if(p0.isNotEmpty){
if(checkIsZeroInput != '0'){
getNumeric = checkIsZeroInput + getNumeric;
}
}else{
getNumeric = checkIsZeroInput.substring(0, checkIsZeroInput.length - 1);
}
String formatNumeric = NumberFormatter.numberCurrency(
double.parse(getNumeric), 'Rp ', 'id_ID', decimalDigits: 0).replaceAll('.', ',');
inputController.text = formatNumeric;
}),
SizedBox(height: 8),
ButtonView(
name: 'Next',
onPressed: () {
Navigator.pop(context);
int formatIntParse = int.parse(inputController.text.replaceAll('Rp ', '').replaceAll(',', ''));
showModalBottomSheet(context: context, builder: (context) => OptionsStartingInvest(totalInvest: formatIntParse));
},
width: SizeConfig.width,
heightWrapContent: true,
contentPadding: EdgeInsets.symmetric(vertical: 16),
marginVertical: 0,
)
],
),
InputInvestmentView(
selectedPlan: text,
nextMove: (value) {
Navigator.pop(context);
int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll(',', ''));
showModalBottomSheet(context: context, builder: (context) => OptionsStartingInvest(totalInvest: formatIntParse));
},
),
],
),

View File

@ -1,17 +1,12 @@
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/subscribe/total_payment_view.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/plan/view/step_invest_plan/result_total_product.dart';
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart';
import 'package:flutter/material.dart';
class Product {
String name, type;
double totalPercent;
Product(this.name, this.type, this.totalPercent);
}
class ResultOptionsProduct extends StatelessWidget {
final int totalInvest;
const ResultOptionsProduct({super.key, required this.totalInvest});
@ -19,9 +14,9 @@ class ResultOptionsProduct extends StatelessWidget {
@override
Widget build(BuildContext context) {
List<Product> listProduct = [
Product('Gemilang Dana Kas Maxima', 'Money Market', 0.7),
Product('Gemilang Dana Likuid', 'Bonds', 0.2),
Product('Gemilang Kas 2 Kelas A', 'Shares', 0.1)
Product(name: 'Gemilang Dana Kas Maxima', type: 'Money Market', totalPercent: 0.7),
Product(name: 'Gemilang Dana Likuid', type: 'Bonds', totalPercent: 0.2),
Product(name: 'Gemilang Kas 2 Kelas A', type: 'Shares', totalPercent: 0.1)
];
return Container(
@ -44,7 +39,7 @@ class ResultOptionsProduct extends StatelessWidget {
color: ColorPalette.slate800
),
),
const Icon(Icons.close_rounded, color: ColorPalette.slate400)
Icon(Icons.close_rounded, color: ColorPalette.slate400)
],
),
const SizedBox(height: 32),
@ -58,8 +53,8 @@ class ResultOptionsProduct extends StatelessWidget {
color: Colors.white,
border: Border.all(color: ColorPalette.slate200),
borderRadius: BorderRadius.circular(12),
boxShadow: [
const BoxShadow(
boxShadow: const [
BoxShadow(
color: Color(0XFF1E293B0A)
)
]
@ -76,10 +71,10 @@ class ResultOptionsProduct extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(e.value.name,
Text(e.value.name ?? '',
style: const TextStyle(
fontWeight: FontWeight.w700,
color: ColorPalette.slate800
fontWeight: FontWeight.w700,
color: ColorPalette.slate800,
),
),
const SizedBox(height: 4,),
@ -90,17 +85,18 @@ class ResultOptionsProduct extends StatelessWidget {
color: ColorPalette.investTypeBgColor[e.value.type],
borderRadius: BorderRadius.circular(40)
),
child: Text(e.value.type,
child: Text(e.value.type ?? '',
style: TextStyle(
color: ColorPalette.investTypeColor[e.value.type],
fontWeight: FontWeight.w600
color: ColorPalette.investTypeColor[e.value.type],
fontWeight: FontWeight.w600,
fontSize: 12
),
),
)
],
),
),
Text('${(e.value.totalPercent * 100).toInt()} %',
Text('${(e.value.totalPercent! * 100).toInt()} %',
style: const TextStyle(
fontWeight: FontWeight.w700,
fontSize: 16,
@ -135,11 +131,14 @@ class ResultOptionsProduct extends StatelessWidget {
ButtonView(
name: 'Next',
onPressed: () {
Navigator.pop(context);
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => ResultTotalProduct(listProduct: listProduct, totalInvest: totalInvest)
builder: (context) =>
TotalPaymentView(
listProduct: listProduct,
totalInvest: totalInvest,
)
);
},
width: SizeConfig.width,

View File

@ -1,11 +1,6 @@
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart';
import 'package:flutter/material.dart';
class PlanViewModel extends ChangeNotifier {
bool isAgreement = false;
void setAgreement() {
isAgreement = !isAgreement;
notifyListeners();
}
List<Product> listProduct = [];
}

View File

@ -9,9 +9,12 @@ 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/product/product_chart_view.dart';
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view/product_chart_view.dart';
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view/step_subscribe/select_goal_investing.dart';
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart';
import 'package:flutter/material.dart';
import 'package:group_button/group_button.dart';
import 'package:provider/provider.dart';
class Time {
int value;
@ -97,58 +100,65 @@ class _ProductViewState extends State<ProductView> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox(
child: Stack(
children: [
const ImageView(image: PathAssets.imgDashboardAccount),
Column(
children: [
const SizedBox(
height: 50,
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BackButtonView(),
Wrap(
spacing: 12,
children: [
Icon(Icons.search_rounded, color: ColorPalette.blue200, size: 32),
Icon(Icons.file_download_outlined, color: ColorPalette.blue200, size: 32),
Icon(Icons.star_outline_rounded, color: ColorPalette.blue200, size: 32)
],
)
],
return ChangeNotifierProvider(
create: (context) => ProductViewModel(),
child: Scaffold(
body: SizedBox(
child: Stack(
children: [
const ImageView(image: PathAssets.imgDashboardAccount),
Column(
children: [
const SizedBox(
height: 50,
),
),
const SizedBox(
height: 24,
),
headContainer(),
const SizedBox(
height: 24,
),
Expanded(
child: contentContainer()
)
],
)
],
const Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BackButtonView(),
Wrap(
spacing: 12,
children: [
Icon(Icons.search_rounded, color: ColorPalette.blue200, size: 32),
Icon(Icons.file_download_outlined, color: ColorPalette.blue200, size: 32),
Icon(Icons.star_outline_rounded, color: ColorPalette.blue200, size: 32)
],
)
],
),
),
const SizedBox(
height: 24,
),
headContainer(),
const SizedBox(
height: 24,
),
Expanded(
child: contentContainer()
)
],
)
],
),
),
),
bottomNavigationBar: Container(
height: SizeConfig.height * .1,
padding: const EdgeInsets.symmetric(horizontal: 24),
child: ButtonView(
name: 'Buy',
onPressed: () {
},
height: SizeConfig.height * 0.06,
marginVertical: 16,
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,
),
),
),
);
@ -581,18 +591,10 @@ class _ProductViewState extends State<ProductView> {
},
selectedMachineType
),
const Padding(
padding: EdgeInsets.only(top: 16, bottom: 8),
child: Text(
"Today's Investment Estimated Value",
style: TextStyle(
fontWeight: FontWeight.w600,
color: ColorPalette.slate800
),
),
),
SizedBox(height: 16),
TextFormView(
name: '',
name: "Today's Investment Estimated Value",
nameSize: 14,
ctrl: machineController,
keyboardType: TextInputType.number,
contentPadding: EdgeInsets.all(12),

View File

@ -0,0 +1,282 @@
import 'dart:ffi';
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';
import 'package:cims_apps/application/component/modal_redirect_app.dart';
import 'package:cims_apps/application/component/success_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/number_formatter.dart';
import 'package:cims_apps/core/utils/size_config.dart';
import 'package:cims_apps/features/bottom_navigation_view.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Payment {
String name;
int fee;
double? discount;
Payment({required this.name, required this.fee, this.discount = 1});
}
class PaymentMethodView extends StatefulWidget {
final int totalInvest;
const PaymentMethodView({super.key, required this.totalInvest });
@override
State<PaymentMethodView> createState() => _PaymentMethodViewState();
}
class _PaymentMethodViewState extends State<PaymentMethodView> {
int selectedPayment = 0;
Payment currentPayment = Payment(name: 'Wallet Pay', fee: 2500);
List<Payment> listInstantPayment = [
Payment(name: 'Wallet Pay', fee: 2500),
Payment(name: 'Link Start', fee: 2500),
Payment(name: 'Shopping Pay', fee: 2500, discount: 0.5),
Payment(name: 'Fund', fee: 2500, discount: 0.2)
];
List<Payment> listTransferBank = [
Payment(name: 'BCA', fee: 2500),
Payment(name: 'Bank Republik Indonesia', fee: 2500)
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(
height: 70,
title: 'Payment Method'
),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
child: Column(
children: [
segmentTitle(Icons.bolt_rounded, 'Instant Payment'),
Wrap(
runSpacing: 16,
children: listInstantPayment.asMap().entries.map((e) {
return cardPayment(e.value, e.key);
}).toList(),
),
const SizedBox(height: 8),
segmentTitle(Icons.account_balance_outlined, 'Transfer Bank'),
Wrap(
runSpacing: 16,
children: listTransferBank.asMap().entries.map((e) {
return cardPayment(e.value, e.key + (listInstantPayment.length));
}).toList(),
),
SizedBox(height: 16,)
],
),
),
bottomNavigationBar: Container(
padding: const EdgeInsets.all(24),
child: segmentBottom(currentPayment)
),
);
}
Widget segmentTitle(IconData? icon, String title) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Row(
children: [
Icon(icon, color: ColorPalette.primary),
const SizedBox(width: 8),
Text(title,
style: const TextStyle(
color: ColorPalette.slate800,
fontWeight: FontWeight.w600,
fontSize: 16
),
)
],
),
);
}
Widget cardPayment(Payment value, int index) {
return GestureDetector(
onTap: () {
setState(() {
selectedPayment = index;
currentPayment = value;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14),
border: Border.all(color: selectedPayment == index ? ColorPalette.primary : ColorPalette.slate200)
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(value.name,
style: const TextStyle(
fontSize: 16
),
),
RichText(
text: TextSpan(
text: 'Payment fee ',
style: const TextStyle(
fontFamily: 'Manrope',
color: ColorPalette.slate400,
),
children: [
TextSpan(
text: '${NumberFormatter.numberCurrency(value.fee, 'Rp ', 'id_ID', decimalDigits: 0)} ',
style: TextStyle(
decoration: value.discount != 1 ? TextDecoration.lineThrough : TextDecoration.none,
fontFamily: 'Manrope',
color: ColorPalette.slate400,
),
),
if(value.discount != 1)...[
TextSpan(
text: value.discount == 0 ? 'Free' : NumberFormatter.numberCurrency(value.fee * value.discount!, 'Rp ', 'id_ID', decimalDigits: 0),
style: const TextStyle(
fontFamily: 'Manrope',
color: ColorPalette.primary,
),
)
]
]
)
)
],
)
],
),
AnimatedContainer(
duration: const Duration(milliseconds: 200),
width: 16,
height: 16,
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: selectedPayment == index ? ColorPalette.primary : Colors.white,
border: Border.all(color: selectedPayment == index ? ColorPalette.primary : ColorPalette.slate200, width: 1.5)
),
child: const Icon(Icons.done_rounded, color: Colors.white, size: 12),
)
],
)
],
),
),
);
}
Widget segmentBottom(Payment currentPayment) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
rowTotal('Total Invest', widget.totalInvest),
rowTotal('Payment Fee', (currentPayment.fee * currentPayment.discount!).toInt()),
Row(
children: [
Expanded(child: Divider(color: ColorPalette.slate200, height: 1,)),
Icon(Icons.add, size: 10,)
],
),
rowTotal('Total Payment', widget.totalInvest + (currentPayment.fee * currentPayment.discount!).toInt()),
SizedBox(height: 24),
ButtonView(
name: 'Buy',
textSize: 18,
marginVertical: 0,
width: SizeConfig.width,
heightWrapContent: true,
contentPadding: EdgeInsets.symmetric(vertical: 16),
onPressed: () {
List<String> redirect = ['Shopping Pay'];
if(redirect.contains(currentPayment.name)){
showModalBottomSheet(
context: context,
builder: (context) {
return ModalRedirectApp(value: currentPayment.name);
},
);
}
routePush(context, page: SuccessView(
img: PathAssets.imgPaymentSuccess,
textTitle: 'Payment Success!',
subtitle: RichText(
text: TextSpan(
text: 'Payment With ',
style: TextStyle(
fontFamily: 'Manrope',
fontWeight: FontWeight.w600,
fontSize: 16,
color: ColorPalette.slate500
),
children: [
TextSpan(
text: currentPayment.name,
style: TextStyle(
fontFamily: 'Manrope',
fontWeight: FontWeight.w700,
fontSize: 16,
color: ColorPalette.slate800
)
),
TextSpan(
text: ' successful',
style: TextStyle(
fontFamily: 'Manrope',
fontWeight: FontWeight.w600,
fontSize: 16,
color: ColorPalette.slate500
)
)
]
)
),
nextRoute: () {
routePush(context, page: BottomNavigationView(), routeType: RouteType.pushRemove);
},
));
},
)
],
);
}
Widget rowTotal(String title, int value) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title,
style: const TextStyle(
fontWeight: FontWeight.w600,
color: ColorPalette.slate500,
fontSize: 16
),
),
Text(NumberFormatter.numberCurrency(value, 'Rp', 'id_ID', decimalDigits: 0),
style: const TextStyle(
fontWeight: FontWeight.w700,
color: ColorPalette.slate800,
fontSize: 16
),
)
],
);
}
}

View File

@ -0,0 +1,83 @@
import 'package:cims_apps/application/component/subscribe/goal_investing_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/theme/color_palette.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 SelectGoalInvesting extends StatelessWidget {
const SelectGoalInvesting({super.key});
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => ProductViewModel(),)
],
child: Consumer<ProductViewModel>(
builder: (context, provider, child) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16)
),
padding: EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Your Goal in Investing',
style: TextStyle(
fontWeight: FontWeight.w700,
color: ColorPalette.slate800,
fontSize: 18
),
),
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.close_rounded, color: ColorPalette.slate400)
)
],
),
SizedBox(height: 32),
GoalInvestingView(
onListSelected: (p0) {
Navigator.pop(context);
showModalBottomSheet(
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,
)
);
},
);
},
);
},
)
],
),
);
}
),
);
}
}

View File

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class Product {
String? name, type;
double? yield;
double? priceUnit, funds, totalPercent;
Product({this.name, this.type, this.yield, this.priceUnit, this.funds, this.totalPercent = 1});
}
class ProductViewModel extends ChangeNotifier {
static Product selectedProduct = Product();
Product get getSelectedProduct => selectedProduct;
double totalInvestment = 0;
void setSelectedProduct(Product product) {
selectedProduct = product;
notifyListeners();
}
void setTotalInvestment(double value) {
totalInvestment = value;
notifyListeners();
}
}

View File

@ -39,6 +39,10 @@ class MyApp extends StatelessWidget {
secondary: const Color(0xFFFECDA6),
onBackground: const Color(0xFFA9A9A9),
),
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: Colors.white,
surfaceTintColor: Colors.white
)
// useMaterial3: true,
),
initialRoute: initialRoute,