33 Commits

Author SHA1 Message Date
e441c56bab fix: product view 2024-03-06 16:43:02 +07:00
e513df325c fix: homepage view 2024-03-05 19:25:49 +07:00
23e1a6628f fix: merge origin dev 2024-03-05 15:43:52 +07:00
4b07219928 Merge pull request 'bayu/dev' (#19) from bayu/dev into dev
Reviewed-on: #19
2024-03-05 15:27:21 +07:00
9cdda42b8b Merge branch 'dev' of https://git.empatnusabangsa.com/nugrohob825/cims_apps into bayu/dev 2024-03-05 15:26:46 +07:00
6f5d3ccca8 feat: transaction 2024-03-05 15:25:44 +07:00
eb99ad9d7f feat: profile page 2024-02-29 17:14:05 +07:00
ff515e2621 fix: styling step registration 2024-02-26 15:11:28 +07:00
f057a346c2 fix: add validation form data bank 2024-02-26 15:05:47 +07:00
f84fe1017d fix: add validation form data id card 2024-02-26 14:00:19 +07:00
27ba55314b fix: styling take picture 2024-02-26 13:52:29 +07:00
59e046bd92 fix: add validation form email 2024-02-26 13:44:27 +07:00
4461b78565 fix: add validation form 2024-02-26 13:21:20 +07:00
f2f688f9f3 fix: route back button 2024-02-26 12:30:18 +07:00
d1adfd2ab0 Merge pull request 'bayu/dev' (#18) from bayu/dev into dev
Reviewed-on: #18
2024-02-26 00:25:27 +07:00
33b2ab85e3 merge conflict 2024-02-26 00:23:54 +07:00
6a43a3dcaf fix: styling dashboard public 2024-02-26 00:17:58 +07:00
db1280b272 fix: select data bank 2024-02-25 23:43:48 +07:00
ae4f9c25c4 fix: component select form 2024-02-25 19:58:41 +07:00
a87afe16cb Merge pull request 'yoga' (#17) from yoga into dev
Reviewed-on: #17
2024-02-23 14:57:36 +07:00
1904e9a4a3 Merge branch 'dev' into yoga 2024-02-23 14:56:39 +07:00
d79959c47f fix: validation input investment 2024-02-23 14:56:06 +07:00
38837bd4f8 feat: expandable text component 2024-02-22 18:13:54 +07:00
d966108e9e fix: more detail redeem product 2024-02-22 17:01:56 +07:00
506f364b87 fix: layout dashboard public 2024-02-22 16:27:15 +07:00
506480d812 fix: button terms and condition 2024-02-22 15:56:09 +07:00
a6ea9a2314 Merge pull request 'yoga' (#16) from yoga into dev
Reviewed-on: #16
2024-02-22 14:46:52 +07:00
176261923d fix: provider view model agreement redeem and product 2024-02-22 14:43:40 +07:00
a3148d8210 feat: wip redeem portfolio 2024-02-21 19:45:22 +07:00
6e03fa5fa7 fix: validation questioner risk profile 2024-02-21 13:26:29 +07:00
de1782c2c2 fix: see more product view 2024-02-20 19:57:52 +07:00
89a79276a6 feat: new icon bottom navigation bar 2024-02-20 19:33:32 +07:00
4737a91ab1 Merge pull request 'bayu/dev' (#15) from bayu/dev into dev
Reviewed-on: #15
2024-02-20 18:49:59 +07:00
84 changed files with 3863 additions and 1113 deletions

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -49,6 +49,30 @@ 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';
static const String iconCat = 'assets/icons/icon-cat.png';
static const String iconProfile = 'assets/icons/icon-profile.png';
static const String iconPadlock = 'assets/icons/icon-padlock.png';
static const String iconCard = 'assets/icons/icon-card.png';
static const String iconSetting = 'assets/icons/icon-setting.png';
static const String iconFaqs = 'assets/icons/icon-faqs.png';
static const String iconLogout = 'assets/icons/icon-logout.png';
static const String iconEducation = 'assets/icons/icon-education.png';
static const String iconFund = 'assets/icons/icon-fund.png';
static const String iconHome = 'assets/icons/icon-home.png';
static const String iconShop = 'assets/icons/icon-shop.png';
static const String iconGadgetOutline =
'assets/icons/icon-gadget-outline.png';
/// IMAGE /// IMAGE
static const String imgSplashLogo = 'assets/images/splash-logo.png'; static const String imgSplashLogo = 'assets/images/splash-logo.png';
@@ -83,7 +107,28 @@ class PathAssets {
static const String imgGuide1 = 'assets/images/img-guide1.png'; static const String imgGuide1 = 'assets/images/img-guide1.png';
static const String imgGuide2 = 'assets/images/img-guide2.png'; static const String imgGuide2 = 'assets/images/img-guide2.png';
static const String imgOpenShopping = 'assets/images/img-open-shopping.png'; static const String imgOpenShopping = 'assets/images/img-open-shopping.png';
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 String imgDashboardProfile =
'assets/images/img-dashboard-profile.png';
static const String imgEmptyTransaction =
'assets/images/img-empty-transaction.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

@@ -0,0 +1,100 @@
import 'package:cims_apps/application/component/image/image_view.dart';
import 'package:cims_apps/application/theme/color_palette.dart';
import 'package:cims_apps/core/utils/size_config.dart';
import 'package:flutter/material.dart';
class CardTransactionView extends StatelessWidget {
final VoidCallback onTap;
final String iconPath, type, amount, subs, step;
final String? timeTransaction;
const CardTransactionView({
Key? key,
required this.step,
required this.type,
required this.amount,
required this.iconPath,
required this.subs,
required this.onTap,
this.timeTransaction,
}) : super(key: key);
@override
Widget build(BuildContext context) {
TextTheme textTheme = Theme.of(context).textTheme;
return GestureDetector(
onTap: onTap,
child: Container(
margin: const EdgeInsets.symmetric(vertical: 16.0),
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 1, color: ColorPalette.slate200),
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: SizeConfig.width * .4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
ImageView(
image: iconPath, width: SizeConfig.width * .12),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
type,
style: textTheme.headlineSmall,
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Text(
amount,
style: textTheme.headlineSmall,
),
),
],
)),
SizedBox(
width: SizeConfig.width * .4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
height: SizeConfig.height * .08,
child: Text(
subs,
style: const TextStyle(color: ColorPalette.primary),
)),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
step == 'waiting'
? const Icon(Icons.access_time_sharp,
color: ColorPalette.slate400)
: const SizedBox(),
step == 'waiting'
? Text(timeTransaction.toString())
: const SizedBox(),
const Padding(
padding: EdgeInsets.only(left: 16.0),
child: Icon(Icons.arrow_forward_ios),
),
],
),
],
)),
],
),
),
);
}
}

View File

@@ -0,0 +1,44 @@
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/core/utils/size_config.dart';
import 'package:flutter/material.dart';
class EmptyCardTransaction extends StatelessWidget {
final VoidCallback onPressedButton;
const EmptyCardTransaction({Key? key, required this.onPressedButton})
: super(key: key);
@override
Widget build(BuildContext context) {
TextTheme textTheme = Theme.of(context).textTheme;
return Container(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ImageView(
image: PathAssets.imgEmptyTransaction,
width: SizeConfig.width * .4,
),
Text(
'No Transaction Yet',
style: textTheme.headlineSmall,
),
Text(
"Let's keep building your investment for even greater financial growth!",
style: textTheme.bodyMedium,
textAlign: TextAlign.center,
),
ButtonView(
name: 'Investing Now',
width: SizeConfig.width * .5,
onPressed: onPressedButton,
),
],
),
),
);
}
}

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

@@ -0,0 +1,119 @@
import 'package:cims_apps/application/component/expandable_widget/see_more_less_widget.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 ExpandableWidget extends StatelessWidget {
final String? content;
final double? fontSize;
final int maxLinesToShow;
final Alignment? alignmentMore;
final bool? hideTextMore;
final bool? hideIconMore;
ExpandableWidget({
super.key,
required this.content,
this.fontSize,
this.maxLinesToShow = 1,
this.alignmentMore,
this.hideTextMore = false,
this.hideIconMore = true,
});
ValueNotifier<bool> expanded = ValueNotifier(false);
@override
Widget build(BuildContext context) {
final TextSpan textSpan = TextSpan(
text: content ?? "",
style: TextStyle(
fontSize: fontSize ?? 16.0,
color: ColorPalette.slate400,
),
);
final TextPainter textPainter = TextPainter(
text: textSpan,
maxLines: expanded.value ? null : maxLinesToShow,
textDirection: TextDirection.ltr,
strutStyle: StrutStyle(
fontSize: fontSize ?? 16.0,
)
);
textPainter.layout(maxWidth: SizeConfig.width);
final int numberOfLines = textPainter.computeLineMetrics().length;
return ValueListenableBuilder(
valueListenable: expanded,
builder: (context, values, _) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
if (!expanded.value && numberOfLines >= maxLinesToShow) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
content ?? "",
maxLines: maxLinesToShow,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: fontSize ?? 16.0,
color: ColorPalette.slate400,
),
),
/* See More :: type 1 - See More | 2 - See Less */
SeeMoreLessWidget(
textData: 'See More',
type: 1,
section: 1,
onSeeMoreLessTap: () {
expanded.value = true;
},
alignment: alignmentMore,
hideIconMore: hideIconMore!,
hideTextMore: hideTextMore!,
),
/* See More :: type 1 - See More | 2 - See Less */
],
);
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
content ?? "",
style: TextStyle(
fontSize: fontSize ?? 16.0,
color: ColorPalette.slate400,
),
),
if (expanded.value && numberOfLines >= maxLinesToShow)
/* See Less :: type 1 - See More | 2 - See Less */
SeeMoreLessWidget(
textData: 'See Less',
type: 2,
section: 1,
onSeeMoreLessTap: () {
expanded.value = false;
},
alignment: alignmentMore,
hideIconMore: hideIconMore!,
hideTextMore: hideTextMore!,
),
/* See Less :: type 1 - See More | 2 - See Less */
],
);
}
},
),
],
);
},
);
}
}

View File

@@ -0,0 +1,74 @@
import 'package:cims_apps/application/theme/color_palette.dart';
import 'package:flutter/material.dart';
class SeeMoreLessWidget extends StatelessWidget {
final String? textData;
final int? type; /* type 1 - See More | 2 - See Less */
final Function? onSeeMoreLessTap;
final int?
section; /* 1: About the course | 2 - Who can take up this course? | 3 - Mentors | 4 - Course Video Reviews */
final Alignment? alignment;
final bool hideTextMore;
final bool hideIconMore;
const SeeMoreLessWidget({
super.key,
required this.textData,
required this.type,
required this.onSeeMoreLessTap,
required this.section,
required this.alignment,
required this.hideTextMore,
required this.hideIconMore,
});
@override
Widget build(BuildContext context) {
return Align(
alignment: alignment ?? Alignment.centerLeft,
child: InkWell(
onTap: () {
if (onSeeMoreLessTap != null) {
onSeeMoreLessTap!();
}
},
child: Text.rich(
softWrap: true,
style: const TextStyle(
color: ColorPalette.primary,
),
textAlign: TextAlign.start,
TextSpan(
text: "",
children: [
if(!hideTextMore)
TextSpan(
text: textData,
style: const TextStyle(
color: ColorPalette.primary,
decoration: TextDecoration.underline,
),
),
if(!hideTextMore && !hideIconMore)
const WidgetSpan(
child: SizedBox(
width: 3.0,
),
),
if(!hideIconMore)
WidgetSpan(
child: Icon(
(type == 1)
? Icons.keyboard_arrow_down
: Icons.keyboard_arrow_up,
color: ColorPalette.slate300,
size: 28,
),
),
],
),
),
),
);
}
}

View File

@@ -84,7 +84,7 @@ class NumericPad extends StatelessWidget {
} }
Widget spaceWidget() { Widget spaceWidget() {
return Expanded( return const Expanded(
child: SizedBox() child: SizedBox()
); );
} }
@@ -96,13 +96,15 @@ class NumericPad extends StatelessWidget {
onNumberSelected(number); onNumberSelected(number);
}, },
child: Container( child: Container(
color: Colors.transparent,
padding: EdgeInsets.symmetric(vertical: SizeConfig.height * .028), padding: EdgeInsets.symmetric(vertical: SizeConfig.height * .028),
child: Text( child: Text(
number, number,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: const TextStyle(
fontSize: 28, fontSize: 28,
fontWeight: FontWeight.bold fontWeight: FontWeight.bold,
color: ColorPalette.slate800
), ),
), ),
), ),
@@ -116,9 +118,14 @@ class NumericPad extends StatelessWidget {
onTap: () { onTap: () {
onNumberSelected(''); onNumberSelected('');
}, },
child: Icon( child: Container(
Icons.highlight_remove, color: Colors.transparent,
padding: EdgeInsets.symmetric(vertical: SizeConfig.height * .028),
child: const Icon(
Icons.backspace_outlined,
size: 28, size: 28,
color: ColorPalette.slate800,
),
), ),
) )
); );

View File

@@ -0,0 +1,57 @@
import 'package:cims_apps/application/component/expandable_widget/expandable_widget.dart';
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: ExpandableWidget(
content: desc,
maxLinesToShow: 3,
)
)
],
),
);
}
}

View File

@@ -1,4 +1,5 @@
import 'package:cims_apps/application/assets/path_assets.dart'; import 'package:cims_apps/application/assets/path_assets.dart';
import 'package:cims_apps/application/component/expandable_widget/expandable_widget.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: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';
@@ -73,20 +74,20 @@ class RiskProfile extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Container( Container(
padding: EdgeInsets.all(24), padding: const EdgeInsets.all(24),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
riskProfile.type, riskProfile.type,
style: TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 24, fontSize: 24,
color: ColorPalette.white color: ColorPalette.white
), ),
), ),
SizedBox(height: 16,), const SizedBox(height: 16,),
Text('Total Score :', const Text('Total Score :',
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 16, fontSize: 16,
@@ -94,7 +95,7 @@ class RiskProfile extends StatelessWidget {
), ),
), ),
Text('$totalScore', Text('$totalScore',
style: TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 28, fontSize: 28,
color: ColorPalette.white color: ColorPalette.white
@@ -107,20 +108,20 @@ class RiskProfile extends StatelessWidget {
), ),
), ),
), ),
SizedBox( const SizedBox(
height: 24, height: 24,
), ),
Text( ExpandableWidget(
riskProfile.desc, content: riskProfile.desc,
style: TextStyle( hideTextMore: true,
color: ColorPalette.slate500, hideIconMore: false,
fontSize: 16 maxLinesToShow: 4,
) alignmentMore: Alignment.center,
), ),
SizedBox( const SizedBox(
height: 24, height: 24,
), ),
Text( const Text(
'Suitable Product', 'Suitable Product',
style: TextStyle( style: TextStyle(
color: ColorPalette.slate800, color: ColorPalette.slate800,
@@ -128,7 +129,7 @@ class RiskProfile extends StatelessWidget {
fontSize: 18 fontSize: 18
), ),
), ),
SizedBox( const SizedBox(
height: 16, height: 16,
), ),
rowSuitableProduct ? rowSuitableProduct ?
@@ -137,7 +138,7 @@ class RiskProfile extends StatelessWidget {
return Expanded( return Expanded(
child: Container( child: Container(
margin: EdgeInsets.only(left: e.key != 0 ? 12 : 0), margin: EdgeInsets.only(left: e.key != 0 ? 12 : 0),
padding: EdgeInsets.all(16), padding: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: ColorPalette.slate200), border: Border.all(color: ColorPalette.slate200),
borderRadius: BorderRadius.circular(6) borderRadius: BorderRadius.circular(6)
@@ -146,18 +147,18 @@ class RiskProfile extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
padding: EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: riskProfile.color.withOpacity(0.1) color: riskProfile.color.withOpacity(0.1)
), ),
child: Image.asset(e.value['icon'], width: SizeConfig.width * 0.07, color: riskProfile.color) child: Image.asset(e.value['icon'], width: SizeConfig.width * 0.07, color: riskProfile.color)
), ),
SizedBox( const SizedBox(
height: 12, height: 12,
), ),
Text(e.value['desc'], Text(e.value['desc'],
style: TextStyle( style: const TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: ColorPalette.slate800 color: ColorPalette.slate800
@@ -173,7 +174,7 @@ class RiskProfile extends StatelessWidget {
runSpacing: 16, runSpacing: 16,
children: riskProfile.suitableProduct.map((e) { children: riskProfile.suitableProduct.map((e) {
return Container( return Container(
padding: EdgeInsets.all(16), padding: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
border: Border.all(color: ColorPalette.slate200), border: Border.all(color: ColorPalette.slate200),
@@ -181,7 +182,7 @@ class RiskProfile extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
Container( Container(
padding: EdgeInsets.all(8), padding: const EdgeInsets.all(8),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
@@ -189,12 +190,12 @@ class RiskProfile extends StatelessWidget {
), ),
child: Image.asset(e['icon'], width: SizeConfig.width * 0.07, color: riskProfile.color) child: Image.asset(e['icon'], width: SizeConfig.width * 0.07, color: riskProfile.color)
), ),
SizedBox( const SizedBox(
width: 12, width: 12,
), ),
Expanded( Expanded(
child: Text(e['desc'], child: Text(e['desc'],
style: TextStyle( style: const TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: ColorPalette.slate800 color: ColorPalette.slate800

View File

@@ -47,6 +47,7 @@ class SelectFormView extends StatelessWidget {
bottomSheet() { bottomSheet() {
showModalBottomSheet<void>( showModalBottomSheet<void>(
context: context, context: context,
isDismissible: false,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: _borderRadius, topLeft: _borderRadius,
@@ -82,7 +83,10 @@ class SelectFormView extends StatelessWidget {
), ),
), ),
IconButton( IconButton(
onPressed: () => Navigator.pop(context), onPressed: () {
ctrl?.clear();
Navigator.pop(context);
},
icon: const Icon( icon: const Icon(
Icons.clear, Icons.clear,
size: 26, size: 26,
@@ -134,7 +138,7 @@ class SelectFormView extends StatelessWidget {
onTap: () { onTap: () {
stateSetter(() { stateSetter(() {
ctrl?.text = e.text; ctrl?.text = e.text;
onSelect(e.key); onSelect(e.text);
}); });
}, },
), ),
@@ -148,7 +152,9 @@ class SelectFormView extends StatelessWidget {
name: 'Select', name: 'Select',
marginVertical: 4.0, marginVertical: 4.0,
onPressed: () { onPressed: () {
if (ctrl!.text.isNotEmpty) {
Navigator.pop(context); Navigator.pop(context);
}
}, },
) )
], ],

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

@@ -1,3 +1,5 @@
import 'dart:math';
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/numeric_pad/numeric_pad.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/application/theme/color_palette.dart';
@@ -6,9 +8,13 @@ import 'package:cims_apps/core/utils/size_config.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class InputInvestmentView extends StatefulWidget { class InputInvestmentView extends StatefulWidget {
final String selectedPlan; final String? currentPlan;
final void Function()? changePlan;
final int? currentPrice;
final int? minimumPrice;
final int? maximumPrice;
final void Function(String value) nextMove; final void Function(String value) nextMove;
const InputInvestmentView({super.key, required this.selectedPlan, required this.nextMove}); const InputInvestmentView({super.key, required this.nextMove, this.currentPlan, this.minimumPrice, this.maximumPrice, this.currentPrice, this.changePlan});
@override @override
State<InputInvestmentView> createState() => _InputInvestmentViewState(); State<InputInvestmentView> createState() => _InputInvestmentViewState();
@@ -17,10 +23,35 @@ class InputInvestmentView extends StatefulWidget {
class _InputInvestmentViewState extends State<InputInvestmentView> { class _InputInvestmentViewState extends State<InputInvestmentView> {
TextEditingController inputController = TextEditingController(); TextEditingController inputController = TextEditingController();
void validationInputValue(String currentValue) {
currentValue = currentValue.replaceAll('Rp ', '').replaceAll('.', '');
if(currentValue.isEmpty){
currentValue = '0';
}
double parseValue = double.parse(currentValue);
if(widget.minimumPrice != null){
if(parseValue <= widget.minimumPrice!){
parseValue = widget.minimumPrice!.toDouble();
}
}
if(widget.maximumPrice != null){
if(parseValue >= widget.maximumPrice!){
parseValue = widget.maximumPrice!.toDouble();
}
}
inputController.text = NumberFormatter.numberCurrency(parseValue, 'Rp ', 'id_ID', decimalDigits: 0);
}
@override @override
void initState() { void initState() {
// TODO: implement initState // TODO: implement initState
if(widget.currentPrice != null){
inputController.text = NumberFormatter.numberCurrency(widget.currentPrice, 'Rp ', 'id_ID', decimalDigits: 0);
}else{
inputController.text = 'Rp 0'; inputController.text = 'Rp 0';
}
super.initState(); super.initState();
} }
@@ -41,23 +72,25 @@ class _InputInvestmentViewState extends State<InputInvestmentView> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SizedBox(height: 16),
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if(widget.currentPlan != null)
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text(widget.selectedPlan, Text(widget.currentPlan ?? '',
style: TextStyle( style: const TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
), ),
), ),
Row( InkWell(
borderRadius: BorderRadius.circular(16),
onTap: widget.changePlan,
child: const Row(
children: [ children: [
Icon(Icons.change_circle_outlined, color: ColorPalette.primary, size: 20), Icon(Icons.change_circle_outlined, color: ColorPalette.primary, size: 20),
SizedBox(width: 4), SizedBox(width: 4),
@@ -69,28 +102,23 @@ class _InputInvestmentViewState extends State<InputInvestmentView> {
), ),
) )
], ],
),
) )
], ],
), ),
TextField( TextField(
controller: inputController, controller: inputController,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: const TextStyle(
fontSize: 28, fontSize: 28,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: ColorPalette.slate800 color: ColorPalette.slate800
), ),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
onChanged: (value) { onChanged: (value) {
value = value.replaceAll('Rp ', '').replaceAll('.', ''); validationInputValue(value);
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( decoration: const InputDecoration(
enabledBorder: UnderlineInputBorder( enabledBorder: UnderlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: ColorPalette.primary, color: ColorPalette.primary,
@@ -99,30 +127,36 @@ class _InputInvestmentViewState extends State<InputInvestmentView> {
) )
), ),
), ),
SizedBox(height: 12), const SizedBox(height: 12),
Text('Minimum Budget Rp1,000,000', if(widget.minimumPrice != null)
style: TextStyle( Text('Minimum ${NumberFormatter.numberCurrency(widget.minimumPrice, 'Rp ', 'id_ID')}',
style: const TextStyle(
color: ColorPalette.slate400, color: ColorPalette.slate400,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w600 fontWeight: FontWeight.w600
), ),
), ),
SizedBox(height: 16), if(widget.maximumPrice != null)
Text('Maximum ${NumberFormatter.numberCurrency(widget.maximumPrice, 'Rp ', 'id_ID')}',
style: const TextStyle(
color: ColorPalette.slate400,
fontSize: 16,
fontWeight: FontWeight.w600
),
),
const SizedBox(height: 16),
NumericPad(onNumberSelected: (p0) { NumericPad(onNumberSelected: (p0) {
String checkIsZeroInput = inputController.text.replaceAll('Rp ', '').replaceAll(',', ''); String currentValue = inputController.text;
String getNumeric = p0;
if(p0.isNotEmpty){ if(p0.isNotEmpty){
if(checkIsZeroInput != '0'){ if(currentValue != '0'){
getNumeric = checkIsZeroInput + getNumeric; currentValue = currentValue + p0;
} }
}else{ }else{
getNumeric = checkIsZeroInput.substring(0, checkIsZeroInput.length - 1); currentValue = currentValue.substring(0, currentValue.length - 1);
} }
String formatNumeric = NumberFormatter.numberCurrency( validationInputValue(currentValue);
double.parse(getNumeric), 'Rp ', 'id_ID', decimalDigits: 0).replaceAll('.', ',');
inputController.text = formatNumeric;
}), }),
SizedBox(height: 8), const SizedBox(height: 24),
ButtonView( ButtonView(
name: 'Next', name: 'Next',
onPressed: () { onPressed: () {
@@ -130,7 +164,7 @@ class _InputInvestmentViewState extends State<InputInvestmentView> {
}, },
width: SizeConfig.width, width: SizeConfig.width,
heightWrapContent: true, heightWrapContent: true,
contentPadding: EdgeInsets.symmetric(vertical: 16), contentPadding: const EdgeInsets.symmetric(vertical: 16),
marginVertical: 0, marginVertical: 0,
) )
], ],
@@ -138,6 +172,6 @@ class _InputInvestmentViewState extends State<InputInvestmentView> {
), ),
], ],
), ),
);; );
} }
} }

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,13 @@ 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.',
onTap: () {
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 +158,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 +169,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 +189,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

@@ -2,6 +2,7 @@ import 'dart:io';
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/image/image_view.dart'; import 'package:cims_apps/application/component/image/image_view.dart';
import 'package:cims_apps/application/component/take_picture_screen/take_picture_screen.dart'; import 'package:cims_apps/application/component/take_picture_screen/take_picture_screen.dart';
import 'package:cims_apps/application/theme/color_palette.dart'; import 'package:cims_apps/application/theme/color_palette.dart';
@@ -94,10 +95,8 @@ class _DisplayPictureScreenState extends State<DisplayPictureScreen> {
return Consumer<SubmissionDataViewModel>( return Consumer<SubmissionDataViewModel>(
builder: (context, provider, child) { builder: (context, provider, child) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: CustomAppBar(
title: const Text('Preview'), height: SizeConfig.height * .08, title: 'Preview'),
automaticallyImplyLeading: false,
),
body: Container( body: Container(
padding: const EdgeInsets.symmetric(horizontal: 24.0), padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Column( child: Column(

View File

@@ -1,5 +1,6 @@
import 'package:camera/camera.dart'; import 'package:camera/camera.dart';
import 'package:cims_apps/application/assets/path_assets.dart'; import 'package:cims_apps/application/assets/path_assets.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/image/image_view.dart';
import 'package:cims_apps/application/component/take_picture_screen/display_picture_screen.dart'; import 'package:cims_apps/application/component/take_picture_screen/display_picture_screen.dart';
import 'package:cims_apps/core/route/route.dart'; import 'package:cims_apps/core/route/route.dart';
@@ -27,7 +28,6 @@ class TakePictureScreenState extends State<TakePictureScreen> {
late String _takeContent; late String _takeContent;
Future<void> changeFlash() async { Future<void> changeFlash() async {
await _controller.setFlashMode(FlashMode.auto);
setState(() { setState(() {
isFlash = !isFlash; isFlash = !isFlash;
}); });
@@ -44,6 +44,7 @@ class TakePictureScreenState extends State<TakePictureScreen> {
// Next, initialize the controller. This returns a Future. // Next, initialize the controller. This returns a Future.
_initializeControllerFuture = _controller.initialize(); _initializeControllerFuture = _controller.initialize();
_takeContent = widget.takeContent; _takeContent = widget.takeContent;
_controller.setFlashMode(isFlash ? FlashMode.torch : FlashMode.off);
} }
@override @override
@@ -57,9 +58,10 @@ class TakePictureScreenState extends State<TakePictureScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Fill this out in the next steps. // Fill this out in the next steps.
return Scaffold( return Scaffold(
appBar: AppBar( appBar: CustomAppBar(
title: const Text('Registration'), title: 'Registration',
actions: [ height: SizeConfig.height * .08,
trailing: [
IconButton( IconButton(
onPressed: () { onPressed: () {
changeFlash(); changeFlash();

View File

@@ -190,6 +190,18 @@ class TextFormView extends StatelessWidget {
color: focusedBorderColor ?? ColorPalette.greyBorder, color: focusedBorderColor ?? ColorPalette.greyBorder,
), ),
), ),
errorBorder: OutlineInputBorder(
borderRadius: _borderRadius,
borderSide: BorderSide(
color: ColorPalette.red600
)
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: _borderRadius,
borderSide: BorderSide(
color: ColorPalette.red600
)
),
border: OutlineInputBorder(borderRadius: _borderRadius), border: OutlineInputBorder(borderRadius: _borderRadius),
suffixIcon: suffixIcon, suffixIcon: suffixIcon,
prefixIcon: prefixIcon, prefixIcon: prefixIcon,

View File

@@ -5,17 +5,20 @@ class TextTitle extends StatelessWidget {
final String title; final String title;
final Color? color; final Color? color;
final double? fontSize; final double? fontSize;
final TextAlign? textAlign;
const TextTitle({ const TextTitle({
Key? key, Key? key,
required this.title, required this.title,
this.color, this.color,
this.fontSize, this.fontSize,
this.textAlign,
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Text( return Text(
title, title,
textAlign: textAlign,
style: TextStyle( style: TextStyle(
fontSize: fontSize ?? 20, fontSize: fontSize ?? 20,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,

View File

@@ -75,6 +75,7 @@ class ColorPalette {
static const Color backgroundBlueLight = Color(0xFFEBF3FD); static const Color backgroundBlueLight = Color(0xFFEBF3FD);
static const Color blue50 = Color(0xFFEFF6FF); static const Color blue50 = Color(0xFFEFF6FF);
static const Color blue200 = Color(0xFFBFDBFE); static const Color blue200 = Color(0xFFBFDBFE);
static const Color blue600 = Color(0xFF2563EB);
static const Color blue900 = Color(0xFF1E3A8A); static const Color blue900 = Color(0xFF1E3A8A);
static const Color slate50 = Color(0xFFF8FAFC); static const Color slate50 = Color(0xFFF8FAFC);
static const Color slate200 = Color(0xFFE2E8F0); static const Color slate200 = Color(0xFFE2E8F0);
@@ -90,8 +91,11 @@ class ColorPalette {
static const Color cyan100 = Color(0xFFCFFAFE); static const Color cyan100 = Color(0xFFCFFAFE);
static const Color cyan500 = Color(0xFF06B6D4); static const Color cyan500 = Color(0xFF06B6D4);
static const Color green100 = Color(0xFFDCFCE7); static const Color green100 = Color(0xFFDCFCE7);
static const Color green300 = Color(0xFF86EFAC);
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 Color red50 = Color(0xFFFEF2F2);
static const Map<String, Color> investTypeColor = { static const Map<String, Color> investTypeColor = {
'Money Market': purple500, 'Money Market': purple500,
@@ -106,4 +110,16 @@ class ColorPalette {
'Sharia': green100, 'Sharia': green100,
'Bonds': cyan100 'Bonds': cyan100
}; };
static const Map<String, Color> riskColor = {
'Moderate': orange500,
'Conservative': green500,
'Aggressive': cyan500
};
static const Map<String, Color> textRiskColor = {
'Moderate': orange500,
'Conservative': green300,
'Aggressive': cyan500
};
} }

View File

@@ -1,3 +1,5 @@
import 'package:intl/intl.dart';
class StringUtils { class StringUtils {
static bool emailValidation(String email) { static bool emailValidation(String email) {
return RegExp( return RegExp(
@@ -13,4 +15,12 @@ class StringUtils {
return RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*?[\W_])(?=.{8,})') return RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*?[\W_])(?=.{8,})')
.hasMatch(password); .hasMatch(password);
} }
static String formatTime(DateTime? dateTime) {
if (dateTime != null) {
DateFormat formatter = DateFormat('HH:mm:ss');
return formatter.format(dateTime);
}
return '--:--:--';
}
} }

View File

@@ -52,7 +52,7 @@ class PhoneNumberView extends StatelessWidget {
width: SizeConfig.width * .23, width: SizeConfig.width * .23,
padding: padding:
const EdgeInsets.symmetric(horizontal: 16.0), const EdgeInsets.symmetric(horizontal: 16.0),
margin: const EdgeInsets.only(right: 16), margin: const EdgeInsets.only(right: 16, left: 1, top: 1, bottom: 1),
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: ColorPalette.grey, color: ColorPalette.grey,
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(

View File

@@ -31,10 +31,11 @@ class RegistrationView extends StatelessWidget {
), ),
), ),
builder: (BuildContext context) { builder: (BuildContext context) {
var flutterView = View.of(context);
return Padding( return Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
top: MediaQueryData.fromView( top: MediaQueryData.fromView(
WidgetsBinding.instance.window, flutterView,
).padding.top, ).padding.top,
), ),
child: const OtpView( child: const OtpView(

View File

@@ -6,19 +6,26 @@ 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/submission_parent.dart'; import 'package:cims_apps/features/auth/registration/view/submission_data/submission_parent.dart';
import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ModelDataBank {
final String? title, subtitle;
ModelDataBank(this.title, this.subtitle);
}
class ConfirmBankAccount extends StatelessWidget { class ConfirmBankAccount extends StatelessWidget {
const ConfirmBankAccount({Key? key}) : super(key: key); const ConfirmBankAccount({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
List listData = [ final listDataBank =
{'title': 'Bank Name', 'subtitle': 'Bank Mandiri'}, ModalRoute.of(context)!.settings.arguments as List<ModelDataBank>;
{'title': 'Account Number', 'subtitle': '123002212084'},
{'title': 'Account Owner Name', 'subtitle': 'Muhamad Rosyidin'}, return ChangeNotifierProvider(
{'title': 'Name on ID card', 'subtitle': 'Muhamad Rosyidin'}, create: (context) => SubmissionDataViewModel(),
]; builder: (context, child) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
toolbarHeight: 70, toolbarHeight: 70,
@@ -42,7 +49,9 @@ class ConfirmBankAccount extends StatelessWidget {
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: SizedBox( child: SizedBox(
height: SizeConfig.height * .85, height: SizeConfig.height * .85,
child: Column( child: Consumer<SubmissionDataViewModel>(
builder: (context, provider, child) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -53,7 +62,7 @@ class ConfirmBankAccount extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
...listData.map((e) { ...listDataBank.map((e) {
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 16.0), padding: const EdgeInsets.only(bottom: 16.0),
child: Column( child: Column(
@@ -61,12 +70,13 @@ class ConfirmBankAccount extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
e['title'], e.title!,
style: const TextStyle( style: const TextStyle(
color: ColorPalette.slate400, fontSize: 16), color: ColorPalette.slate400,
fontSize: 16),
), ),
Text( Text(
e['subtitle'], e.subtitle!,
style: const TextStyle( style: const TextStyle(
fontSize: 16, fontSize: 16,
color: ColorPalette.slate800, color: ColorPalette.slate800,
@@ -98,15 +108,18 @@ class ConfirmBankAccount extends StatelessWidget {
name: 'Confirm', name: 'Confirm',
width: SizeConfig.width * .42, width: SizeConfig.width * .42,
onPressed: () { onPressed: () {
routePush(context, page: const SubmissionParent()); routePush(context,
page: const SubmissionParent());
}, },
), ),
], ],
) )
], ],
), );
}),
), ),
), ),
); );
});
} }
} }

View File

@@ -0,0 +1,108 @@
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:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ListBankView extends StatelessWidget {
final ValueChanged<String> onSelect;
const ListBankView({Key? key, required this.onSelect}) : super(key: key);
@override
Widget build(BuildContext context) {
var textTheme = Theme.of(context).textTheme;
return ChangeNotifierProvider(
create: (context) => SubmissionDataViewModel(),
builder: (context, child) {
return Scaffold(
appBar: CustomAppBar(
height: SizeConfig.height * .1, title: 'Select Bank'),
body: Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Consumer<SubmissionDataViewModel>(
builder: (context, provider, child) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ImageView(
image: PathAssets.imgGuideBank,
width: SizeConfig.width * .35,
),
Expanded(
child: Text(
'Make sure the bank you choose is a bank account in your own name ',
style: textTheme.bodyLarge,
),
)
],
),
TextFormView(
name: '',
hintText: 'Search bank',
ctrl: provider.ctrlBankNameSearch,
contentPadding: const EdgeInsets.symmetric(vertical: 0),
prefixIcon: const Icon(
Icons.search,
color: ColorPalette.slate500,
),
),
Expanded(
child: SingleChildScrollView(
child: Column(
children: provider.listBank.asMap().entries.map((e) {
bool selectedBank =
e.key.toString() == provider.idx;
return Card(
elevation: 0,
color: selectedBank
? ColorPalette.blue50
: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(12)),
),
child: ListTile(
title: Text(
e.value.text,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: selectedBank
? ColorPalette.primary
: ColorPalette.slate500,
),
),
onTap: () {
provider.changeBank(e.key.toString());
provider.selectBank(e.value.text);
},
),
);
}).toList(),
),
),
),
ButtonView(
name: 'Select',
marginVertical: 8.0,
onPressed: () {
onSelect(provider.valueBank);
Navigator.pop(context);
},
),
],
);
}),
),
);
});
}
}

View File

@@ -1,13 +1,13 @@
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/image/image_view.dart'; import 'package:cims_apps/application/component/image/image_view.dart';
import 'package:cims_apps/application/component/select_form/select_form_view.dart';
import 'package:cims_apps/application/component/text_caption/text_caption.dart'; import 'package:cims_apps/application/component/text_caption/text_caption.dart';
import 'package:cims_apps/application/component/text_form/text_form_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/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/data_bank/guide_screen.dart'; import 'package:cims_apps/features/auth/registration/view/submission_data/data_bank/guide_screen.dart';
import 'package:cims_apps/features/auth/registration/view/submission_data/data_bank/list_bank_view.dart';
import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -19,6 +19,40 @@ class SubmitBankAccount extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
showSearchBank(TextEditingController valueCtrl) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: false,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.zero,
),
),
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
var flutterView = View.of(context);
return Padding(
padding: EdgeInsets.only(
top: MediaQueryData.fromView(
flutterView,
).padding.top,
),
child: ListBankView(
onSelect: (value) {
setState(() {
valueCtrl.text = value;
});
},
),
);
},
);
},
);
}
return MultiProvider( return MultiProvider(
providers: [ providers: [
ChangeNotifierProvider( ChangeNotifierProvider(
@@ -29,22 +63,44 @@ class SubmitBankAccount extends StatelessWidget {
return SizedBox( return SizedBox(
child: Consumer<SubmissionDataViewModel>( child: Consumer<SubmissionDataViewModel>(
builder: (context, provider, child) { builder: (context, provider, child) {
return SingleChildScrollView( return SizedBox(
height: SizeConfig.height * .8,
child: Form(
key: provider.formKeySubmitDataBank,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const TextCaption(title: 'Input your bank account data'), const TextCaption(title: 'Input your bank account data'),
SelectFormView( TextFormView(
name: 'Bank Name', name: 'Bank Name',
hintText: 'Select Bank', hintText: 'Select bank',
listItem: provider.listBank, readOnly: true,
ctrl: provider.ctrlBankName, ctrl: provider.ctrlBankName,
onSelect: (value) {}, onTap: () {
showSearchBank(provider.ctrlBankName);
},
suffixIcon: const Icon(
Icons.keyboard_arrow_down_outlined,
),
validator: (value) {
if (value!.isEmpty) {
return 'Field must be filled';
}
return null;
},
), ),
TextFormView( TextFormView(
name: 'Account Number', name: 'Account Number',
hintText: 'Input Account Number', hintText: 'Input Account Number',
ctrl: provider.ctrlNoAccountBank,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
validator: (value) {
if (value!.isEmpty) {
return 'Field must be filled';
}
return null;
},
trailingTitleWidget: SizedBox( trailingTitleWidget: SizedBox(
width: 24, width: 24,
child: GestureDetector( child: GestureDetector(
@@ -59,6 +115,13 @@ class SubmitBankAccount extends StatelessWidget {
TextFormView( TextFormView(
name: 'Account Owner Name', name: 'Account Owner Name',
hintText: 'Input Account Name', hintText: 'Input Account Name',
ctrl: provider.ctrlNameAccountBank,
validator: (value) {
if (value!.isEmpty) {
return 'Field must be filled';
}
return null;
},
), ),
const Text( const Text(
"Make sure the account you use is in your name, not someone else's", "Make sure the account you use is in your name, not someone else's",
@@ -70,16 +133,29 @@ class SubmitBankAccount extends StatelessWidget {
ButtonView( ButtonView(
name: 'Next', name: 'Next',
onPressed: () { onPressed: () {
if (provider.formKeySubmitDataBank.currentState!
.validate()) {
provider
.submitDataBank(
bankName: provider.ctrlBankName.text,
accountNumber: provider.ctrlNoAccountBank.text,
accountName: provider.ctrlNameAccountBank.text,
)
.then((values) {
provider.next(context).then((value) { provider.next(context).then((value) {
if (value) { if (value) {
routePush(context, routePush(context,
page: const ConfirmBankAccount()); page: const ConfirmBankAccount(),
arguments: values);
} }
}); });
});
}
}, },
) )
], ],
), ),
),
); );
}), }),
); );

View File

@@ -56,8 +56,12 @@ 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
@@ -65,8 +69,11 @@ class _QuestionViewState extends State<QuestionView> {
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

@@ -14,12 +14,12 @@ class RiskProfileView extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
width: SizeConfig.width, width: SizeConfig.width,
height: SizeConfig.height, height: SizeConfig.height * .8,
padding: EdgeInsets.all(24), padding: const EdgeInsets.all(24),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Column( const Column(
children: [ children: [
ImageView(image: PathAssets.imgDataReport), ImageView(image: PathAssets.imgDataReport),
SizedBox( SizedBox(
@@ -48,7 +48,7 @@ class RiskProfileView extends StatelessWidget {
), ),
Column( Column(
children: [ children: [
Row( const Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
ImageView( ImageView(
@@ -68,7 +68,7 @@ class RiskProfileView extends StatelessWidget {
) )
], ],
), ),
SizedBox( const SizedBox(
height: 24, height: 24,
), ),
ButtonView( ButtonView(

View File

@@ -1,3 +1,4 @@
import 'package:cims_apps/application/component/button/back_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';
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';
@@ -66,21 +67,33 @@ class _SubmissionParentState extends State<SubmissionParent> {
return ChangeNotifierProvider( return ChangeNotifierProvider(
create: (context) => SubmissionDataViewModel(), create: (context) => SubmissionDataViewModel(),
builder: (context, child) { builder: (context, child) {
return WillPopScope( return PopScope(
onWillPop: () async { canPop: false,
onPopInvoked: (didPop) async {
if (didPop) {
return;
}
await routePush(context, await routePush(context,
page: const BottomNavigationView(), page: const BottomNavigationView(),
routeType: RouteType.pushReplace); routeType: RouteType.pushReplace);
return false;
}, },
child: Consumer<SubmissionDataViewModel>( child: Consumer<SubmissionDataViewModel>(
builder: (context, provider, child) { builder: (context, provider, child) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
height: SizeConfig.height * .1, title: 'Registration'), height: SizeConfig.height * .1,
body: Stack( title: 'Registration',
children: [ leading: BackButtonView(
Column( onPress: () {
routePush(
context,
page: const BottomNavigationView(),
routeType: RouteType.pushReplace,
);
},
),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@@ -89,8 +102,7 @@ class _SubmissionParentState extends State<SubmissionParent> {
horizontal: 16.0, vertical: 16.0), horizontal: 16.0, vertical: 16.0),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: children: List.generate(provider.stepAmount, (index) {
List.generate(provider.stepAmount, (index) {
return _stepItem( return _stepItem(
isCurrentStep: isCurrentStep:
provider.getCurrentStep == index + 1 || provider.getCurrentStep == index + 1 ||
@@ -100,16 +112,13 @@ class _SubmissionParentState extends State<SubmissionParent> {
), ),
), ),
Expanded( Expanded(
child: Container( child: SingleChildScrollView(
padding: padding: const EdgeInsets.symmetric(horizontal: 16.0),
const EdgeInsets.symmetric(horizontal: 16.0),
child: _content(provider.getCurrentStep), child: _content(provider.getCurrentStep),
), ),
), ),
], ],
), ),
],
),
); );
}), }),
); );

View File

@@ -176,7 +176,9 @@ class SubmitDataIdCard extends StatelessWidget {
return SingleChildScrollView( return SingleChildScrollView(
child: Consumer<SubmissionDataViewModel>( child: Consumer<SubmissionDataViewModel>(
builder: (context, provider, child) { builder: (context, provider, child) {
return Column( return Form(
key: provider.formKeySubmitIdCard,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const TextCaption( const TextCaption(
@@ -184,14 +186,35 @@ class SubmitDataIdCard extends StatelessWidget {
TextFormView( TextFormView(
name: 'NIK', name: 'NIK',
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
validator: (value) {
if (value!.isEmpty) {
return 'Field must be filled';
}
return null;
},
),
TextFormView(
name: 'Full Name',
validator: (value) {
if (value!.isEmpty) {
return 'Field must be filled';
}
return null;
},
), ),
TextFormView(name: 'Full Name'),
DatePickerView( DatePickerView(
name: 'Birth Date', name: 'Birth Date',
ctrl: provider.ctrlBirthDate, ctrl: provider.ctrlBirthDate,
maxDate: DateTime.now(), maxDate: DateTime.now(),
isMultipleSelection: false, isMultipleSelection: false,
enabled: true), enabled: true,
validatorDate: (value) {
if (value!.isEmpty) {
return 'Field must be filled';
}
return null;
},
),
photoDocument(provider), photoDocument(provider),
Container( Container(
width: SizeConfig.width, width: SizeConfig.width,
@@ -241,14 +264,19 @@ class SubmitDataIdCard extends StatelessWidget {
ButtonView( ButtonView(
name: 'Next', name: 'Next',
onPressed: () async { onPressed: () async {
if (provider.formKeySubmitIdCard.currentState!
.validate()) {
await provider.next(context).then((value) { await provider.next(context).then((value) {
if (value) { if (value) {
routePush(context, page: const SubmissionParent()); routePush(context,
page: const SubmissionParent());
} }
}); });
}
}, },
) )
], ],
),
); );
}), }),
); );

View File

@@ -15,41 +15,70 @@ import 'package:provider/provider.dart';
class SubmitEmail extends StatelessWidget { class SubmitEmail extends StatelessWidget {
const SubmitEmail({Key? key}) : super(key: key); const SubmitEmail({Key? key}) : super(key: key);
Widget _emailVerify() { Widget _emailVerify(BuildContext context, SubmissionDataViewModel provider) {
return Column( var textTheme = Theme.of(context).textTheme;
return Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const TextCaption(title: 'Check your e-mail'),
const ImageView(image: PathAssets.imgEmail), const ImageView(image: PathAssets.imgEmail),
Align( Align(
alignment: Alignment.center, alignment: Alignment.center,
child: RichText( child: RichText(
textAlign: TextAlign.center, textAlign: TextAlign.center,
text: TextSpan(children: [ text: TextSpan(children: [
const TextSpan( TextSpan(
text: text:
'We have sent a verification link to your e-mail. \nPlease check your email for ', 'We have sent a verification link to your e-mail. \nPlease check your email for ',
style: TextStyle( style: textTheme.displayMedium,
color: Colors.black,
decoration: TextDecoration.none,
),
), ),
TextSpan( TextSpan(
recognizer: TapGestureRecognizer()..onTap = () {}, recognizer: TapGestureRecognizer()
..onTap = () async {
await provider.next(context).then((value) {
if (value) {
routePush(context, page: const SubmissionParent());
}
});
},
text: 'verification', text: 'verification',
style: const TextStyle( style: const TextStyle(
color: Colors.blue, color: Colors.blue,
), ),
), ),
const TextSpan( TextSpan(
text: ' to \ncontinue registration.', text: ' to \ncontinue registration.',
style: TextStyle( style: textTheme.displayMedium,
color: Colors.black,
decoration: TextDecoration.none,
),
), ),
]), ]),
), ),
), ),
], ],
),
);
}
showEmailVerify(BuildContext context, SubmissionDataViewModel provider) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: false,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.zero,
),
),
builder: (context) {
var flutterView = View.of(context);
return Padding(
padding: EdgeInsets.only(
top: MediaQueryData.fromView(flutterView).padding.top,
),
child: _emailVerify(context, provider),
);
},
); );
} }
@@ -60,16 +89,16 @@ class SubmitEmail extends StatelessWidget {
builder: (context, child) { builder: (context, child) {
return Consumer<SubmissionDataViewModel>( return Consumer<SubmissionDataViewModel>(
builder: (context, provider, child) { builder: (context, provider, child) {
return SingleChildScrollView( return SizedBox(
height: SizeConfig.height * .78,
child: Form(
key: provider.formKeySubmitEmail,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
!provider.isEmailVerify const TextCaption(title: 'Enter your e-mail'),
? const TextCaption(title: 'Enter your e-mail') TextFormView(
: const TextCaption(title: 'Check your e-mail '),
!provider.isEmailVerify
? TextFormView(
name: 'E-mail Address', name: 'E-mail Address',
hintText: 'Input e-mail address', hintText: 'Input e-mail address',
keyboardType: TextInputType.emailAddress, keyboardType: TextInputType.emailAddress,
@@ -82,24 +111,20 @@ class SubmitEmail extends StatelessWidget {
return null; return null;
} }
}, },
// onTap: () { ),
// provider.submitEmail(); SizedBox(height: SizeConfig.height * .43),
// },
)
: _emailVerify(),
SizedBox(height: SizeConfig.height * .42),
ButtonView( ButtonView(
name: 'Next', name: 'Next',
onPressed: () async { onPressed: () async {
await provider.next(context).then((value) { if (provider.formKeySubmitEmail.currentState!
if (value) { .validate()) {
routePush(context, page: const SubmissionParent()); showEmailVerify(context, provider);
} }
});
}, },
) )
], ],
), ),
),
); );
}); });
}); });

View File

@@ -2,6 +2,7 @@ import 'package:cims_apps/application/component/button/button_view.dart';
import 'package:cims_apps/application/component/select_form/select_form_view.dart'; import 'package:cims_apps/application/component/select_form/select_form_view.dart';
import 'package:cims_apps/application/component/text_caption/text_caption.dart'; import 'package:cims_apps/application/component/text_caption/text_caption.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/features/auth/registration/view/submission_data/submission_parent.dart'; import 'package:cims_apps/features/auth/registration/view/submission_data/submission_parent.dart';
import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -17,12 +18,13 @@ class SubmitPersonalData extends StatelessWidget {
builder: (context, child) { builder: (context, child) {
return Consumer<SubmissionDataViewModel>( return Consumer<SubmissionDataViewModel>(
builder: (context, provider, child) { builder: (context, provider, child) {
return SingleChildScrollView( return SizedBox(
height: SizeConfig.height * .78,
child: Form( child: Form(
key: provider.formKeyPersonalData, key: provider.formKeyPersonalData,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
const TextCaption(title: 'Your personal details'), const TextCaption(title: 'Your personal details'),
SelectFormView( SelectFormView(
@@ -31,6 +33,12 @@ class SubmitPersonalData extends StatelessWidget {
ctrl: provider.ctrlOccupation, ctrl: provider.ctrlOccupation,
listItem: provider.listOccupation, listItem: provider.listOccupation,
onSelect: (value) {}, onSelect: (value) {},
validator: (value) {
if (value!.isEmpty) {
return 'Field must be filled';
}
return null;
},
), ),
SelectFormView( SelectFormView(
name: 'Income Level (IDR)', name: 'Income Level (IDR)',
@@ -38,6 +46,12 @@ class SubmitPersonalData extends StatelessWidget {
ctrl: provider.ctrlIncome, ctrl: provider.ctrlIncome,
listItem: provider.listIncome, listItem: provider.listIncome,
onSelect: (value) {}, onSelect: (value) {},
validator: (value) {
if (value!.isEmpty) {
return 'Field must be filled';
}
return null;
},
), ),
SelectFormView( SelectFormView(
name: 'Marital Status', name: 'Marital Status',
@@ -45,6 +59,12 @@ class SubmitPersonalData extends StatelessWidget {
ctrl: provider.ctrlMarital, ctrl: provider.ctrlMarital,
listItem: provider.listMarital, listItem: provider.listMarital,
onSelect: (value) {}, onSelect: (value) {},
validator: (value) {
if (value!.isEmpty) {
return 'Field must be filled';
}
return null;
},
), ),
SelectFormView( SelectFormView(
name: 'Source of Fund', name: 'Source of Fund',
@@ -52,20 +72,28 @@ class SubmitPersonalData extends StatelessWidget {
ctrl: provider.ctrlSourceFund, ctrl: provider.ctrlSourceFund,
listItem: provider.listSourceFund, listItem: provider.listSourceFund,
onSelect: (value) {}, onSelect: (value) {},
validator: (value) {
if (value!.isEmpty) {
return 'Field must be filled';
}
return null;
},
), ),
Align( // SizedBox(height: SizeConfig.height * .18),
alignment: Alignment.bottomCenter, ButtonView(
child: ButtonView( marginVertical: 0,
name: 'Next', name: 'Next',
onPressed: () async { onPressed: () async {
if (provider.formKeyPersonalData.currentState!
.validate()) {
await provider.next(context).then((value) { await provider.next(context).then((value) {
if (value) { if (value) {
routePush(context, routePush(context,
page: const SubmissionParent()); page: const SubmissionParent());
} }
}); });
}
}, },
),
) )
], ],
), ),

View File

@@ -24,15 +24,18 @@ class InitialSignature extends StatelessWidget {
builder: (context, child) { builder: (context, child) {
return Consumer<SubmissionDataViewModel>( return Consumer<SubmissionDataViewModel>(
builder: (context, provider, child) { builder: (context, provider, child) {
return Column( return SizedBox(
height: SizeConfig.height * .8,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const TextCaption(title: 'Draw your digital sign'), const TextCaption(title: 'Draw your digital sign'),
const ImageView(image: PathAssets.frameSignature), const ImageView(image: PathAssets.frameSignature),
const ListTileView( const ListTileView(
title: title:
'Make sure the sign you draw is match with your ID Card'), 'Make sure the sign you draw is match with your ID Card'),
SizedBox(height: SizeConfig.height * .07), SizedBox(height: SizeConfig.height * .1),
ButtonView( ButtonView(
name: 'Next', name: 'Next',
onPressed: () { onPressed: () {
@@ -44,6 +47,7 @@ class InitialSignature extends StatelessWidget {
}, },
) )
], ],
),
); );
}); });
}); });

View File

@@ -3,6 +3,7 @@ import 'package:cims_apps/application/component/button/button_view.dart';
import 'package:cims_apps/application/component/set_pin_view/set_pin_view.dart'; import 'package:cims_apps/application/component/set_pin_view/set_pin_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/route/route.dart';
import 'package:cims_apps/core/utils/size_config.dart';
import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -60,15 +61,11 @@ class TermsAndConditionView extends StatelessWidget {
], ],
), ),
); );
}) }),
], Consumer<SubmissionDataViewModel>(
),
),
bottomNavigationBar: Consumer<SubmissionDataViewModel>(
builder: (context, provider, child) { builder: (context, provider, child) {
return Container( return Padding(
height: 84, padding: const EdgeInsets.only(top: 24.0),
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
@@ -77,7 +74,8 @@ class TermsAndConditionView extends StatelessWidget {
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
}, },
marginVertical: 16, height: SizeConfig.height * .06,
marginVertical: 0,
backgroundColor: ColorPalette.white, backgroundColor: ColorPalette.white,
textColor: ColorPalette.primary, textColor: ColorPalette.primary,
isOutlined: true, isOutlined: true,
@@ -96,11 +94,15 @@ class TermsAndConditionView extends StatelessWidget {
submitPin: (context, pin) {}, submitPin: (context, pin) {},
)); ));
}, },
marginVertical: 16)) height: SizeConfig.height * .06,
marginVertical: 0))
], ],
), ),
); );
}), }),
],
),
),
); );
}); });
} }

View File

@@ -1,5 +1,6 @@
import 'package:camera/camera.dart'; import 'package:camera/camera.dart';
import 'package:cims_apps/application/component/select_form/select_form_view.dart'; import 'package:cims_apps/application/component/select_form/select_form_view.dart';
import 'package:cims_apps/features/auth/registration/view/submission_data/data_bank/confirm_bank_account.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@@ -14,13 +15,21 @@ class SubmissionDataViewModel extends ChangeNotifier {
bool _isEmailVerify = false; bool _isEmailVerify = false;
bool get isEmailVerify => _isEmailVerify; bool get isEmailVerify => _isEmailVerify;
var formKeyPersonalData = GlobalKey<FormState>(); var formKeyPersonalData = GlobalKey<FormState>();
var formKeySubmitEmail = GlobalKey<FormState>();
var formKeySubmitIdCard = GlobalKey<FormState>();
var formKeySubmitDataBank = GlobalKey<FormState>();
TextEditingController ctrlOccupation = TextEditingController(); TextEditingController ctrlOccupation = TextEditingController();
TextEditingController ctrlIncome = TextEditingController(); TextEditingController ctrlIncome = TextEditingController();
TextEditingController ctrlMarital = TextEditingController(); TextEditingController ctrlMarital = TextEditingController();
TextEditingController ctrlSourceFund = TextEditingController(); TextEditingController ctrlSourceFund = TextEditingController();
TextEditingController ctrlBankName = TextEditingController(); TextEditingController ctrlBankName = TextEditingController();
TextEditingController ctrlNameAccountBank = TextEditingController();
TextEditingController ctrlNoAccountBank = TextEditingController();
TextEditingController ctrlBankNameSearch = TextEditingController();
TextEditingController ctrlBirthDate = TextEditingController(); TextEditingController ctrlBirthDate = TextEditingController();
int step = 1; int step = 1;
String? idx;
String valueBank = '';
List<ItemSelectForm> listOccupation = [ List<ItemSelectForm> listOccupation = [
ItemSelectForm('key1', 'Student'), ItemSelectForm('key1', 'Student'),
@@ -44,11 +53,13 @@ class SubmissionDataViewModel extends ChangeNotifier {
]; ];
List<ItemSelectForm> listBank = [ List<ItemSelectForm> listBank = [
ItemSelectForm('key1', 'BCA'), ItemSelectForm('0', 'BCA'),
ItemSelectForm('key2', 'BRI'), ItemSelectForm('1', 'BRI'),
ItemSelectForm('key3', 'BNI'), ItemSelectForm('2', 'BNI'),
ItemSelectForm('key4', 'BANK MANDIRI'), ItemSelectForm('3', 'BANK MANDIRI'),
ItemSelectForm('key5', 'CIMB NIAGA'), ItemSelectForm('4', 'CIMB NIAGA'),
ItemSelectForm('5', 'PERMATA'),
ItemSelectForm('6', 'BANK JATENG'),
]; ];
List<ItemSelectForm> listImg = [ List<ItemSelectForm> listImg = [
@@ -105,4 +116,31 @@ class SubmissionDataViewModel extends ChangeNotifier {
} }
notifyListeners(); notifyListeners();
} }
changeBank(String key) {
idx = key;
notifyListeners();
}
selectBank(String value) {
valueBank = value;
notifyListeners();
}
List<ModelDataBank> listDataBank = [];
Future<List<ModelDataBank>?> submitDataBank(
{required String bankName, accountNumber, accountName}) async {
List<ModelDataBank> listResponse = [
ModelDataBank('Bank Name', bankName),
ModelDataBank('Account Number', accountNumber),
ModelDataBank('Account Owner Name', accountName),
ModelDataBank('Name on ID card', accountName),
];
if (listResponse.first.subtitle != null) {
// listDataBank = listResponse;
return listResponse;
}
return null;
}
} }

View File

@@ -1,11 +1,19 @@
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';
import 'package:cims_apps/features/profile/view/profile_view.dart'; import 'package:cims_apps/features/dashboard/dashboard_account/view/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

@@ -50,7 +50,7 @@ class _HomeViewState extends State<HomeView> {
]; ];
StepVerification listStepVerification = StepVerification listStepVerification =
StepVerification(0, ['Registration', 'Verification', 'Complete']); StepVerification(1, ['Registration', '', 'Verification', '', 'Complete']);
List<Article> listArticle = [ List<Article> listArticle = [
Article( Article(
@@ -69,12 +69,21 @@ class _HomeViewState extends State<HomeView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: const Color(0xffF8FAFC), backgroundColor: ColorPalette.slate50,
body: SizedBox( body: CustomScrollView(
width: SizeConfig.width, slivers: [
height: SizeConfig.height, SliverAppBar(
child: Stack( onStretchTrigger: () async {
},
expandedHeight: 325,
collapsedHeight: 325,
leading: const SizedBox(),
surfaceTintColor: ColorPalette.slate50,
backgroundColor: ColorPalette.slate50,
flexibleSpace: FlexibleSpaceBar(
background: Stack(
children: [ children: [
const ImageView(image: PathAssets.imgDashboardAccount), const ImageView(image: PathAssets.imgDashboardAccount),
Column( Column(
@@ -118,11 +127,18 @@ class _HomeViewState extends State<HomeView> {
), ),
cardInvestType(), cardInvestType(),
const SizedBox( const SizedBox(
height: 32, height: 24,
), ),
Expanded( ],
child: ListView( )
padding: const EdgeInsets.all(0), ],
),
),
floating: true,
snap: true,
),
SliverToBoxAdapter(
child: Column(
children: [ children: [
cardVerification(), cardVerification(),
const SizedBox( const SizedBox(
@@ -135,12 +151,9 @@ class _HomeViewState extends State<HomeView> {
articles(), articles(),
], ],
), ),
),
],
) )
], ],
), ),
),
); );
} }
@@ -279,6 +292,7 @@ class _HomeViewState extends State<HomeView> {
child: Column( child: Column(
children: [ children: [
stepVerification(), stepVerification(),
if(listStepVerification.currentStep < 3)
const SizedBox( const SizedBox(
height: 24, height: 24,
), ),
@@ -291,6 +305,7 @@ class _HomeViewState extends State<HomeView> {
Icon( Icon(
Icons.verified, Icons.verified,
size: 18, size: 18,
color: ColorPalette.slate300,
), ),
SizedBox( SizedBox(
width: 12, width: 12,
@@ -324,6 +339,7 @@ class _HomeViewState extends State<HomeView> {
Icon( Icon(
Icons.verified, Icons.verified,
size: 18, size: 18,
color: ColorPalette.slate300,
), ),
SizedBox( SizedBox(
width: 12, width: 12,
@@ -388,11 +404,11 @@ class _HomeViewState extends State<HomeView> {
borderRadius: BorderRadius.circular(12)), borderRadius: BorderRadius.circular(12)),
child: Column( child: Column(
children: [ children: [
Text( const Text(
"Let's start registering your data to start mutual fund investment at PT Gemilang Indonesia", "Let's start registering your data to start mutual fund investment at PT Gemilang Indonesia",
style: TextStyle(color: ColorPalette.slate500), style: TextStyle(color: ColorPalette.slate500),
), ),
SizedBox( const SizedBox(
height: 16, height: 16,
), ),
ButtonView( ButtonView(
@@ -400,9 +416,9 @@ class _HomeViewState extends State<HomeView> {
width: SizeConfig.width, width: SizeConfig.width,
marginVertical: 0, marginVertical: 0,
heightWrapContent: true, heightWrapContent: true,
contentPadding: EdgeInsets.all(12), contentPadding: const EdgeInsets.all(12),
onPressed: () { onPressed: () {
routePush(context, page: InitialRegistrationStep()); routePush(context, page: const InitialRegistrationStep());
}, },
) )
], ],
@@ -417,57 +433,61 @@ class _HomeViewState extends State<HomeView> {
Widget stepVerification() { Widget stepVerification() {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: listStepVerification.nameStep.asMap().entries.map((e) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: List.generate(
if (e.key != 0) listStepVerification.nameStep.length,
SizedBox( (index) {
width: 30, print(index % 2);
height: 30, if (index % 2 == 0) {
child: Divider( final currentStep = index ~/ 2;
color: listStepVerification.currentStep >= e.key return Column(
? const Color(0xff2563EB)
: const Color(0xffCBD5E1),
),
),
Column(
children: [ children: [
Container( Container(
width: 30, width: 30,
height: 30, height: 30,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: listStepVerification.currentStep <= e.key color: listStepVerification.currentStep <= currentStep
? Colors.white ? Colors.white
: const Color(0xff2563EB), : const Color(0xff2563EB),
border: Border.all( border: Border.all(
color: listStepVerification.currentStep < e.key color: listStepVerification.currentStep < currentStep
? const Color(0xffCBD5E1) ? const Color(0xffCBD5E1)
: const Color(0xff2563EB), : const Color(0xff2563EB),
width: 2)), width: 2,
child: listStepVerification.currentStep <= e.key ),
),
child: listStepVerification.currentStep <= currentStep
? const SizedBox() ? const SizedBox()
: const Icon( : const Icon(
Icons.done_rounded, Icons.done_rounded,
color: Colors.white, color: Colors.white,
), ),
), ),
const SizedBox( const SizedBox(height: 8),
height: 8,
),
Text( Text(
e.value, listStepVerification.nameStep[index],
style: TextStyle( style: TextStyle(
color: listStepVerification.currentStep == e.key color: listStepVerification.currentStep == currentStep
? const Color(0xff2563EB) ? const Color(0xff2563EB)
: Colors.black), : Colors.black,
) ),
],
), ),
], ],
); );
}).toList(), } else {
return SizedBox(
width: 30,
height: 30,
child: Divider(
color: listStepVerification.currentStep > index ~/ 2
? const Color(0xff2563EB)
: const Color(0xffCBD5E1),
),
);
}
},
),
); );
} }
@@ -591,7 +611,7 @@ class _HomeViewState extends State<HomeView> {
color: ColorPalette.green100), color: ColorPalette.green100),
child: Text( child: Text(
article.type, article.type,
style: TextStyle( style: const TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: ColorPalette.green500), color: ColorPalette.green500),
), ),

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

@@ -1,12 +1,8 @@
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';
import 'package:cims_apps/application/component/subscribe/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/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/risk_profile.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/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/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/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/plan/view_model/plan_view_model.dart';
@@ -40,28 +36,34 @@ 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(),
child: Scaffold(
appBar: CustomAppBar(
height: SizeConfig.height * 0.08,
title: 'Investment Plan',
leading: const SizedBox(),
),
body: SingleChildScrollView( body: SingleChildScrollView(
padding: EdgeInsets.all(24), padding: const EdgeInsets.all(24),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
RiskProfile( const RiskProfile(
totalScore: 26, totalScore: 26,
rowSuitableProduct: true rowSuitableProduct: true
), ),
SizedBox( const SizedBox(
height: 32, height: 32,
), ),
Text('Your Goal in Investing', const Text('Your Goal in Investing',
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
color: ColorPalette.slate800, color: ColorPalette.slate800,
fontSize: 18 fontSize: 18
), ),
), ),
SizedBox( const SizedBox(
height: 24, height: 24,
), ),
GoalInvestingView( GoalInvestingView(
@@ -78,6 +80,7 @@ class _PlanViewState extends State<PlanView> {
], ],
), ),
), ),
),
); );
} }
@@ -95,7 +98,7 @@ class _PlanViewState extends State<PlanView> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("It's time to invest", const Text("It's time to invest",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w600 fontWeight: FontWeight.w600
@@ -105,17 +108,20 @@ class _PlanViewState extends State<PlanView> {
onTap: () { onTap: () {
Navigator.pop(context); Navigator.pop(context);
}, },
child: Icon(Icons.close_rounded) child: const Icon(Icons.close_rounded)
) )
], ],
), ),
), ),
Divider(color: ColorPalette.slate200, height: 1), const Divider(color: ColorPalette.slate200, height: 1),
InputInvestmentView( InputInvestmentView(
selectedPlan: text, currentPlan: text,
changePlan: () {
Navigator.pop(context);
},
nextMove: (value) { nextMove: (value) {
Navigator.pop(context); Navigator.pop(context);
int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll(',', '')); int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll('.', ''));
showModalBottomSheet(context: context, builder: (context) => OptionsStartingInvest(totalInvest: formatIntParse)); showModalBottomSheet(context: context, builder: (context) => OptionsStartingInvest(totalInvest: formatIntParse));
}, },
), ),

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,6 +24,10 @@ 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 ChangeNotifierProvider(
create: (context) => PlanViewModel(),
child: Consumer<PlanViewModel>(
builder: (context, provider, child) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
@@ -28,10 +37,21 @@ class ResultOptionsProduct extends StatelessWidget {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Icon(Icons.arrow_back, color: ColorPalette.slate500), GestureDetector(
onTap: () {
Navigator.pop(context);
showModalBottomSheet(
context: context,
builder: (context) {
return OptionsStartingInvest(totalInvest: totalInvest);
},
);
},
child: Icon(Icons.arrow_back, color: ColorPalette.slate500)
),
Text('Results from your risk profile', Text('Results from your risk profile',
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@@ -39,7 +59,13 @@ class ResultOptionsProduct extends StatelessWidget {
color: ColorPalette.slate800 color: ColorPalette.slate800
), ),
), ),
Icon(Icons.close_rounded, color: ColorPalette.slate400) GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.close_rounded, color: ColorPalette.slate400)
)
], ],
), ),
const SizedBox(height: 32), const SizedBox(height: 32),
@@ -111,6 +137,7 @@ class ResultOptionsProduct extends StatelessWidget {
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
routePush(context, page: ProductView(selectedProduct: e.value, seeMore: true));
}, },
child: const Text('See More', child: const Text('See More',
style: TextStyle( style: TextStyle(
@@ -131,13 +158,23 @@ class ResultOptionsProduct extends StatelessWidget {
ButtonView( ButtonView(
name: 'Next', name: 'Next',
onPressed: () { onPressed: () {
Navigator.pop(context);
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: (context) => builder: (context) =>
TotalPaymentView( ChangeNotifierProvider(
create: (context) => PlanViewModel(),
child: Consumer<PlanViewModel>(
builder: (context, planProvider, _) {
return TotalPaymentView(
listProduct: listProduct, listProduct: listProduct,
totalInvest: totalInvest, totalInvest: totalInvest,
isAgree: planProvider.isAgree,
onTapAgree: planProvider.setAgree,
);
}
),
) )
); );
}, },
@@ -150,4 +187,7 @@ class ResultOptionsProduct extends StatelessWidget {
), ),
); );
} }
),
);
}
} }

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,265 @@
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/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 PortfolioDetailView extends StatelessWidget {
const PortfolioDetailView({super.key});
@override
Widget build(BuildContext context) {
List<PortfolioProduct> listProduct = [
PortfolioProduct(
name: 'Gemilang Dana Kas Maxima',
type: 'Money Market',
yield: 8.17,
priceUnit: 2600.79,
funds: 6300000,
totalUnit: 14520
),
PortfolioProduct(
name: 'Gemilang Dana Likuid',
type: 'Sharia',
yield: 6.42,
priceUnit: 1600.79,
funds: 2340000,
totalUnit: 232,
),
PortfolioProduct(
name: 'Gemilang Income Fund',
type: 'Bonds',
yield: 8.17,
priceUnit: 2600.79,
funds: 6300000,
totalUnit: 2450,
)
];
return 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: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Consumer<RedeemProductViewModel>(
builder: (context, provider, child) {
return ListView(
padding: const EdgeInsets.all(24),
children: listProduct.asMap().entries.map((e) {
return cardPortfolio(context, e.value);
}).toList(),
);
}
),
)
)
],
)
],
),
),
),
);
}
Widget cardPortfolio(context, PortfolioProduct product) {
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: [
TextTitle(title: product.name ?? '', fontSize: 16,),
const SizedBox(height: 4),
Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
color: ColorPalette.investTypeBgColor[product.type!]?.withOpacity(0.5) ?? Colors.white,
border: Border.all(width: 2, color: ColorPalette.investTypeColor[product.type!]?.withOpacity(0.4) ?? Colors.white)
),
child: Text(
product.type ?? '',
style: TextStyle(
color: ColorPalette.investTypeColor[product.type!],
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', NumberFormatter.numberCurrency(product.priceUnit, 'Rp ', 'id_ID')),
rowDescription('Number of Units', '${product.totalUnit ?? 0}'),
],
),
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: () {
Provider.of<RedeemProductViewModel>(context, listen: false).setProduct(product);
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,171 @@
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/subscribe/input_investment_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/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,),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(24),
child: cardProduct()
),
InputInvestmentView(
minimumPrice: (provider.getCurrentProduct.priceUnit! * 1).toInt(),
maximumPrice: (provider.getCurrentProduct.priceUnit! * provider.getCurrentProduct.totalUnit!).toInt(),
currentPrice: provider.getAmount!.toInt(),
nextMove: (value) {
String formatValueInput = value.replaceAll('Rp ', '').replaceAll('.', '');
provider.setAmount(double.parse(formatValueInput));
Navigator.pop(context);
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return const RedeemProduct();
},
);
},
)
],
),
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
),
),
)
],
),
)
],
),
);
}
}

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,360 @@
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) {
amountController.text = NumberFormatter.numberCurrency(provider.getAmount!.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.getUnit!,
(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,73 @@
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;
amount = product.priceUnit! * (product.totalUnit! / 2.0);
unit = (product.totalUnit! / 2.0);
notifyListeners();
}
void setAgree() {
isAgree = !isAgree;
notifyListeners();
}
}

View File

@@ -13,6 +13,7 @@ import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view
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/step_subscribe/select_goal_investing.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:flutter/services.dart';
import 'package:group_button/group_button.dart'; import 'package:group_button/group_button.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -24,8 +25,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();
@@ -78,6 +80,8 @@ class _ProductViewState extends State<ProductView> {
}); });
} }
double currentScroll = 0;
@override @override
void initState() { void initState() {
machineController.text = NumberFormatter.numberCurrency(100000, 'Rp ', 'id_ID', decimalDigits: 0); machineController.text = NumberFormatter.numberCurrency(100000, 'Rp ', 'id_ID', decimalDigits: 0);
@@ -103,21 +107,45 @@ class _ProductViewState extends State<ProductView> {
return ChangeNotifierProvider( return ChangeNotifierProvider(
create: (context) => ProductViewModel(), create: (context) => ProductViewModel(),
child: Scaffold( child: Scaffold(
body: SizedBox( body: NotificationListener<ScrollNotification>(
child: Stack( onNotification: (notification) {
children: [ setState(() {
const ImageView(image: PathAssets.imgDashboardAccount), currentScroll = notification.metrics.pixels;
Column( });
children: [ return false;
const SizedBox( },
height: 50, child: CustomScrollView(
slivers: [
SliverAppBar(
toolbarHeight: 70,
expandedHeight: 170,
leadingWidth: 0,
floating: false,
automaticallyImplyLeading: false,
title: AnimatedCrossFade(
firstChild: Text(
widget.selectedProduct.name ?? '',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w700,
fontSize: 18
), ),
const Padding( ),
padding: EdgeInsets.symmetric(horizontal: 24), secondChild: Padding(
child: Row( padding: const EdgeInsets.only(left: 8),
mainAxisAlignment: MainAxisAlignment.spaceBetween, child: BackButtonView(),
children: [ ),
BackButtonView(), crossFadeState: currentScroll >= 85 ? CrossFadeState.showFirst : CrossFadeState.showSecond,
duration: Duration(milliseconds: 200)
),
centerTitle: false,
snap: false,
pinned: true,
backgroundColor: Color(0xFF1745C8).withOpacity(currentScroll >= 95 ? 1 : currentScroll / 95),
surfaceTintColor: ColorPalette.primary,
actions: [
Wrap( Wrap(
spacing: 12, spacing: 12,
children: [ children: [
@@ -125,26 +153,45 @@ class _ProductViewState extends State<ProductView> {
Icon(Icons.file_download_outlined, 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) Icon(Icons.star_outline_rounded, color: ColorPalette.blue200, size: 32)
], ],
) ),
SizedBox(width: 24,)
], ],
), flexibleSpace: Opacity(
), opacity: currentScroll > 0 ? ((95 - currentScroll) / 95) > 0.01 ? ((95 - currentScroll) / 95) : 0 : 1,
const SizedBox( child: Stack(
height: 24, children: [
), ImageView(image: PathAssets.imgDashboardAccount, width: SizeConfig.width, height: 200),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
headContainer(), headContainer(),
const SizedBox( const SizedBox(
height: 24, height: 24,
), ),
Expanded( Container(
child: contentContainer() height: 12,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12)
)
),
) )
], ],
) )
], ],
), ),
), ),
bottomNavigationBar: Container( ),
SliverToBoxAdapter(
child: contentContainer(),
)
],
),
),
bottomNavigationBar: !widget.seeMore ?
Container(
height: SizeConfig.height * .1, height: SizeConfig.height * .1,
padding: const EdgeInsets.symmetric(horizontal: 24), padding: const EdgeInsets.symmetric(horizontal: 24),
child: ButtonView( child: ButtonView(
@@ -159,7 +206,7 @@ class _ProductViewState extends State<ProductView> {
height: SizeConfig.height * 0.06, height: SizeConfig.height * 0.06,
marginVertical: 16, marginVertical: 16,
), ),
), ) : SizedBox(),
), ),
); );
} }
@@ -177,7 +224,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 +237,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
), ),
), ),
@@ -217,8 +265,11 @@ class _ProductViewState extends State<ProductView> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
), ),
child: ListView( child: Column(
children: [ children: [
const SizedBox(
height: 12,
),
ProductChartView( ProductChartView(
tabType: listTab[selectedTab], tabType: listTab[selectedTab],
lastTime: selectedTime.completeName, lastTime: selectedTime.completeName,

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,50 @@ 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(),
child: Consumer<ProductViewModel>(
builder: (context, provider, child) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: InputInvestmentView(
currentPlan: p0,
changePlan: () {
Navigator.pop(context);
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => SelectGoalInvesting(),
);
},
nextMove: (value) { nextMove: (value) {
Navigator.pop(context); Navigator.pop(context);
int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll(',', '')); int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll('.', ''));
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: (context) => builder: (context) =>
TotalPaymentView( ChangeNotifierProvider(
create: (context) => ProductViewModel(),
child: Consumer<ProductViewModel>(
builder: (context, provider, child) {
return TotalPaymentView(
listProduct: [ listProduct: [
provider.getSelectedProduct provider.getSelectedProduct
], ],
totalInvest: formatIntParse, 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

@@ -0,0 +1,165 @@
import 'package:cims_apps/application/assets/path_assets.dart';
import 'package:cims_apps/application/component/image/image_view.dart';
import 'package:cims_apps/application/component/text_title/text_title.dart';
import 'package:cims_apps/application/theme/color_palette.dart';
import 'package:cims_apps/core/utils/size_config.dart';
import 'package:cims_apps/features/dashboard/dashboard_account/view/profile/view_model/profile_view_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class RouteNavigation {
String icon;
String title;
Widget destination;
RouteNavigation(this.icon, this.title, this.destination);
}
class ProfileView extends StatelessWidget {
const ProfileView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
List<RouteNavigation> listGeneral = [
RouteNavigation(PathAssets.iconProfile, 'Personal Data', Container()),
RouteNavigation(PathAssets.iconPadlock, 'Change Password', Container()),
RouteNavigation(PathAssets.iconCard, 'Add Card', Container()),
RouteNavigation(PathAssets.iconSetting, 'Settings', Container())
];
List<RouteNavigation> listPreferences = [
RouteNavigation(PathAssets.iconFaqs, 'FAQs', Container()),
RouteNavigation(PathAssets.iconLogout, 'Log Out', Container())
];
return Provider(
create: (context) => ProfileViewModel(),
child: Scaffold(
body: SizedBox(
width: SizeConfig.width,
height: SizeConfig.height,
child: Stack(
children: [
const Positioned(
left: 0,
right: 0,
top: 0,
bottom: 0,
child: ImageView(image: PathAssets.imgDashboardProfile)
),
Consumer<ProfileViewModel>(
builder: (context, provider, child) {
return ListView(
padding: const EdgeInsets.all(0),
children: [
const SizedBox(
height: 50,
),
const Center(
child: TextTitle(title: 'Profile', color: Colors.white, fontSize: 20,)
),
SizedBox(
height: SizeConfig.height * 0.05,
),
Container(
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
border: Border.all(color: ColorPalette.slate200, width: 1.5)
),
padding: const EdgeInsets.all(8),
child: ImageView(image: PathAssets.iconCat, width: SizeConfig.width * 0.14,),
),
const SizedBox(height: 16),
Center(
child: TextTitle(title: provider.getUser.name ?? '', color: Colors.white, fontSize: 24,)),
Text('Investor ${provider.getUser.risk}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: ColorPalette.textRiskColor[provider.getUser.risk]
),
),
const SizedBox(height: 24),
boxNavigation('General', listGeneral),
const SizedBox(height: 24),
boxNavigation('Preferences', listPreferences)
],
);
}
)
],
),
),
),
);
}
Widget boxNavigation(String title, List<RouteNavigation> list) {
return Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.symmetric(horizontal: 24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title,
style: const TextStyle(
fontWeight: FontWeight.w700,
color: ColorPalette.slate400
),
),
const SizedBox(height: 16),
Wrap(
runSpacing: 16,
children: list.map((e) {
return rowNavigation(
e.icon,
e.title,
e.destination
);
}).toList(),
)
],
),
);
}
Widget rowNavigation(String icon, String text, Widget destination) {
bool isLogout = text == 'Log Out';
Color textColor = isLogout ? ColorPalette.red600 : ColorPalette.slate800;
Color bgLeadingColor = isLogout ? ColorPalette.red50 : ColorPalette.blue50;
Color iconColor = isLogout ? ColorPalette.red600 : ColorPalette.blue600;
return Row(
children: [
Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: bgLeadingColor
),
child: Image.asset(icon, width: SizeConfig.width * 0.05, color: iconColor)
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(text,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: textColor
),
),
),
),
const Icon(Icons.chevron_right_outlined, size: 28, color: ColorPalette.slate400)
],
);
}
}

View File

@@ -0,0 +1,11 @@
class User {
String? name, risk;
User({this.name, this.risk});
}
class ProfileViewModel {
static final User _user = User(name: 'Muhammad Rosyidin', risk: 'Conservative');
User get getUser => _user;
}

View File

@@ -44,8 +44,7 @@ class DashboardPublicView extends StatelessWidget {
return Scaffold( return Scaffold(
body: SingleChildScrollView( body: SingleChildScrollView(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 32.0, bottom: 24.0,
bottom: 8.0,
left: 24.0, left: 24.0,
right: 24.0, right: 24.0,
), ),
@@ -55,10 +54,12 @@ class DashboardPublicView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
SizedBox(height: SizeConfig.height * .06),
ImageView( ImageView(
image: PathAssets.icon1, image: PathAssets.icon1,
width: SizeConfig.width * .35, width: SizeConfig.width * .35,
), ),
SizedBox(height: SizeConfig.height * .02),
Align( Align(
alignment: Alignment.center, alignment: Alignment.center,
heightFactor: 1, heightFactor: 1,
@@ -67,7 +68,7 @@ class DashboardPublicView extends StatelessWidget {
alignment: Alignment.center, alignment: Alignment.center,
child: ImageView( child: ImageView(
image: PathAssets.imgDashboard, image: PathAssets.imgDashboard,
width: SizeConfig.width * .7, width: SizeConfig.width * .8,
), ),
), ),
Row( Row(
@@ -105,7 +106,7 @@ class DashboardPublicView extends StatelessWidget {
provider.loginGoogle(context); provider.loginGoogle(context);
}, },
), ),
SizedBox(height: SizeConfig.height * .15), SizedBox(height: SizeConfig.height * .07),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [

View File

@@ -1,14 +0,0 @@
import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart';
import 'package:cims_apps/core/utils/size_config.dart';
import 'package:flutter/material.dart';
class ProfileView extends StatelessWidget {
const ProfileView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(height: SizeConfig.height * .1, title: 'Profile'),
);
}
}

View File

@@ -0,0 +1,35 @@
import 'package:cims_apps/application/component/card_transaction/card_transaction_view.dart';
import 'package:cims_apps/application/component/card_transaction/empty_card_transaction.dart';
import 'package:cims_apps/features/transaction/viewmodel/transaction_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class CancelView extends StatelessWidget {
const CancelView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Consumer<TransactionViewModel>(
builder: (context, provider, child) => Column(
children: [
if (provider.listOnProcessTransaction.isEmpty)
EmptyCardTransaction(
onPressedButton: () {},
),
...provider.listOnProcessTransaction.map((e) {
return CardTransactionView(
step: 'cancel',
type: 'type',
amount: 'amount',
iconPath: 'iconPath',
subs: 'subs',
onTap: () {},
);
}),
],
),
),
);
}
}

View File

@@ -0,0 +1,37 @@
import 'package:cims_apps/application/component/card_transaction/card_transaction_view.dart';
import 'package:cims_apps/application/component/card_transaction/empty_card_transaction.dart';
import 'package:cims_apps/features/transaction/viewmodel/transaction_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class DoneView extends StatelessWidget {
const DoneView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Consumer<TransactionViewModel>(
builder: (context, provider, child) {
return Column(
children: [
if (provider.listOnProcessTransaction.isEmpty)
EmptyCardTransaction(
onPressedButton: () {},
),
...provider.listOnProcessTransaction.map((e) {
return CardTransactionView(
step: 'done',
type: 'type',
amount: 'amount',
iconPath: 'iconPath',
subs: 'subs',
onTap: () {},
);
}),
],
);
},
),
);
}
}

View File

@@ -0,0 +1,34 @@
import 'package:cims_apps/application/component/card_transaction/card_transaction_view.dart';
import 'package:cims_apps/application/component/card_transaction/empty_card_transaction.dart';
import 'package:cims_apps/features/transaction/viewmodel/transaction_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class OnProcessView extends StatelessWidget {
const OnProcessView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child:
Consumer<TransactionViewModel>(builder: (context, provider, child) {
return Column(children: [
if (provider.listOnProcessTransaction.isEmpty)
EmptyCardTransaction(
onPressedButton: () {},
),
...provider.listOnProcessTransaction.map((e) {
return CardTransactionView(
step: 'on process',
type: 'type',
amount: 'amount',
iconPath: 'iconPath',
subs: 'subs',
onTap: () {},
);
}),
]);
}),
);
}
}

View File

@@ -1,15 +1,124 @@
import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.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/theme/color_palette.dart';
import 'package:cims_apps/core/utils/size_config.dart'; import 'package:cims_apps/core/utils/size_config.dart';
import 'package:cims_apps/features/transaction/view/cancel_view.dart';
import 'package:cims_apps/features/transaction/view/done_view.dart';
import 'package:cims_apps/features/transaction/view/onprocess_view.dart';
import 'package:cims_apps/features/transaction/view/waiting_view.dart';
import 'package:cims_apps/features/transaction/viewmodel/transaction_viewmodel.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_toggle_tab/flutter_toggle_tab.dart';
import 'package:provider/provider.dart';
class TransactionView extends StatelessWidget { class TransactionView extends StatelessWidget {
const TransactionView({Key? key}) : super(key: key); const TransactionView({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<Tab> textTabs = const [
Tab(text: 'Waiting'),
Tab(text: 'On process'),
Tab(text: 'Done'),
Tab(text: 'Cancel'),
];
List<Widget> listTabBarView = const [
WaitingView(),
OnProcessView(),
DoneView(),
CancelView(),
];
return ChangeNotifierProvider(
create: (context) => TransactionViewModel(),
builder: (context, child) {
return Scaffold( return Scaffold(
appBar: backgroundColor: ColorPalette.primary,
CustomAppBar(height: SizeConfig.height * .1, title: 'Transaction'), body: SizedBox(
child: Stack(
children: [
const ImageView(image: PathAssets.imgDashboardAccount),
Column(
children: [
SizedBox(
height: SizeConfig.height * .05,
),
const Center(
child: Text(
'Transaction',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
color: Colors.white),
),
),
SizedBox(
height: SizeConfig.height * .04,
),
Container(
margin: const EdgeInsets.symmetric(horizontal: 24),
child: FlutterToggleTab(
height: SizeConfig.height * .065,
width: SizeConfig.width * .2,
marginSelected: const EdgeInsets.all(8.0),
isScroll: false,
selectedTextStyle: const TextStyle(
color: ColorPalette.primary,
fontWeight: FontWeight.w700,
),
unSelectedTextStyle: const TextStyle(
color: ColorPalette.blackFont,
fontWeight: FontWeight.w700,
),
unSelectedBackgroundColors: const [
ColorPalette.blue50
],
selectedBackgroundColors: const [ColorPalette.white],
labels: const ['Subscribe', 'Reedem'],
selectedLabelIndex: (p0) {},
selectedIndex: 0,
),
),
Expanded(
child: DefaultTabController(
length: textTabs.length,
child: Container(
color: Colors.transparent,
padding: const EdgeInsets.only(top: 32.0),
child: Container(
margin: const EdgeInsets.only(top: 24),
padding: const EdgeInsets.only(top: 16.0),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24),
topRight: Radius.circular(24)),
),
child: Column(
children: [
TabBar(
tabs: textTabs,
indicatorColor: Colors.blueAccent,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 4.0,
),
child: TabBarView(children: listTabBarView),
))
],
),
),
),
)),
],
)
],
),
),
); );
});
} }
} }

View File

@@ -0,0 +1,42 @@
import 'package:cims_apps/application/assets/path_assets.dart';
import 'package:cims_apps/application/component/card_transaction/card_transaction_view.dart';
import 'package:cims_apps/application/component/card_transaction/empty_card_transaction.dart';
import 'package:cims_apps/core/utils/number_formatter.dart';
import 'package:cims_apps/core/utils/string_utils.dart';
import 'package:cims_apps/features/transaction/viewmodel/transaction_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class WaitingView extends StatelessWidget {
const WaitingView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child:
Consumer<TransactionViewModel>(builder: (context, provider, child) {
return Column(
children: [
provider.listWaitingTransaction.isNotEmpty
? CardTransactionView(
onTap: () {},
iconPath: PathAssets.iconEducation,
type: 'Education',
amount: NumberFormatter.numberCurrency(
6000000,
'Rp ',
'id_ID',
decimalDigits: 0,
),
timeTransaction: StringUtils.formatTime(DateTime.now()),
subs: '3 Subscription',
step: 'waiting')
: EmptyCardTransaction(
onPressedButton: () {},
),
],
);
}),
);
}
}

View File

@@ -0,0 +1,8 @@
import 'package:flutter/material.dart';
class TransactionViewModel extends ChangeNotifier {
List listWaitingTransaction = [1];
List listOnProcessTransaction = [];
List listDoneTransaction = [];
List listCancelTransaction = [];
}

View File

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

View File

@@ -259,6 +259,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_toggle_tab:
dependency: "direct main"
description:
name: flutter_toggle_tab
sha256: "90ad0d050f656df677998825f985637d010117a1793828cd7e6dadada4ecd2c5"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
flutter_web_plugins: flutter_web_plugins:
dependency: transitive dependency: transitive
description: flutter description: flutter

View File

@@ -53,6 +53,7 @@ dependencies:
shared_preferences: ^2.2.2 shared_preferences: ^2.2.2
calendar_date_picker2: ^0.5.3 calendar_date_picker2: ^0.5.3
google_sign_in: ^6.2.1 google_sign_in: ^6.2.1
flutter_toggle_tab: ^1.4.1