feat: tax page

This commit is contained in:
efrilm 2025-08-01 15:30:33 +07:00
parent 1384253e8a
commit 8c946ce3d9
5 changed files with 149 additions and 139 deletions

View File

@ -12,6 +12,7 @@ class CustomModalDialog extends StatelessWidget {
final double? maxWidth; final double? maxWidth;
final double? minHeight; final double? minHeight;
final double? maxHeight; final double? maxHeight;
final EdgeInsets? contentPadding;
const CustomModalDialog({ const CustomModalDialog({
super.key, super.key,
@ -23,6 +24,7 @@ class CustomModalDialog extends StatelessWidget {
this.maxWidth, this.maxWidth,
this.minHeight, this.minHeight,
this.maxHeight, this.maxHeight,
this.contentPadding,
}); });
@override @override
@ -100,7 +102,10 @@ class CustomModalDialog extends StatelessWidget {
], ],
), ),
), ),
child, Padding(
padding: contentPadding ?? EdgeInsets.zero,
child: child,
),
], ],
), ),
), ),

View File

@ -1,3 +1,4 @@
import 'package:enaklo_pos/core/components/custom_modal_dialog.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
@ -28,7 +29,8 @@ class _FormTaxDialogState extends State<FormTaxDialog> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
serviceFeeController = TextEditingController(text: widget.serviceChargeValue.toString()); serviceFeeController =
TextEditingController(text: widget.serviceChargeValue.toString());
taxFeeController = TextEditingController(text: widget.taxValue.toString()); taxFeeController = TextEditingController(text: widget.taxValue.toString());
} }
@ -41,19 +43,10 @@ class _FormTaxDialogState extends State<FormTaxDialog> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return CustomModalDialog(
title: Row( title: 'Edit Perhitungan Biaya',
mainAxisAlignment: MainAxisAlignment.spaceBetween, contentPadding: const EdgeInsets.all(16.0),
children: [ child: SingleChildScrollView(
IconButton(
onPressed: () => context.pop(),
icon: const Icon(Icons.close),
),
const Text('Edit Perhitungan Biaya'),
const Spacer(),
],
),
content: SingleChildScrollView(
child: SizedBox( child: SizedBox(
width: context.deviceWidth / 3, width: context.deviceWidth / 3,
child: Column( child: Column(
@ -78,7 +71,8 @@ class _FormTaxDialogState extends State<FormTaxDialog> {
Button.filled( Button.filled(
onPressed: () { onPressed: () {
final taxValue = int.tryParse(taxFeeController.text) ?? 0; final taxValue = int.tryParse(taxFeeController.text) ?? 0;
final serviceChargeValue = int.tryParse(serviceFeeController.text) ?? 0; final serviceChargeValue =
int.tryParse(serviceFeeController.text) ?? 0;
if (widget.onSave != null) { if (widget.onSave != null) {
widget.onSave!(taxValue, serviceChargeValue); widget.onSave!(taxValue, serviceChargeValue);

View File

@ -31,11 +31,11 @@ class _TaxPageState extends State<TaxPage> {
serviceChargeValue: serviceChargeValue, serviceChargeValue: serviceChargeValue,
onSave: (newTaxValue, newServiceChargeValue) { onSave: (newTaxValue, newServiceChargeValue) {
context.read<TaxSettingsBloc>().add( context.read<TaxSettingsBloc>().add(
TaxSettingsEvent.updateSettings( TaxSettingsEvent.updateSettings(
taxValue: newTaxValue, taxValue: newTaxValue,
serviceChargeValue: newServiceChargeValue, serviceChargeValue: newServiceChargeValue,
), ),
); );
}, },
), ),
); );
@ -49,11 +49,11 @@ class _TaxPageState extends State<TaxPage> {
serviceChargeValue: serviceChargeValue, serviceChargeValue: serviceChargeValue,
onSave: (newTaxValue, newServiceChargeValue) { onSave: (newTaxValue, newServiceChargeValue) {
context.read<TaxSettingsBloc>().add( context.read<TaxSettingsBloc>().add(
TaxSettingsEvent.updateSettings( TaxSettingsEvent.updateSettings(
taxValue: newTaxValue, taxValue: newTaxValue,
serviceChargeValue: newServiceChargeValue, serviceChargeValue: newServiceChargeValue,
), ),
); );
}, },
), ),
); );
@ -61,91 +61,110 @@ class _TaxPageState extends State<TaxPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleChildScrollView( return Column(
child: Column( mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, children: [
children: [ const SettingsTitle(
const SettingsTitle('Perhitungan Biaya'), 'Perhitungan Biaya',
const SizedBox(height: 24), subtitle: 'Biaya Layanan dan Pajak',
BlocBuilder<TaxSettingsBloc, TaxSettingsState>( ),
builder: (context, state) { Expanded(
return state.when( child: SingleChildScrollView(
initial: () => const Center(child: CircularProgressIndicator()), child: BlocBuilder<TaxSettingsBloc, TaxSettingsState>(
loading: () => const Center(child: CircularProgressIndicator()), builder: (context, state) {
error: (message) => Center(child: Text('Error: $message')), return state.when(
loaded: (taxModel, serviceChargeValue) { initial: () =>
final items = [ const Center(child: CircularProgressIndicator()),
TaxModel(name: 'Biaya Layanan', type: TaxType.layanan, value: serviceChargeValue), loading: () =>
taxModel, const Center(child: CircularProgressIndicator()),
]; error: (message) => Center(child: Text('Error: $message')),
loaded: (taxModel, serviceChargeValue) {
final items = [
TaxModel(
name: 'Biaya Layanan',
type: TaxType.layanan,
value: serviceChargeValue),
taxModel,
];
return CustomTabBar( return CustomTabBar(
tabTitles: const ['Layanan', 'Pajak'], tabTitles: const ['Layanan', 'Pajak'],
initialTabIndex: 0, initialTabIndex: 0,
tabViews: [ tabViews: [
// LAYANAN TAB // LAYANAN TAB
SizedBox( SizedBox(
child: GridView.builder( child: GridView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: 2, // Add button + 1 service charge item itemCount: 2, // Add button + 1 service charge item
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( padding: const EdgeInsets.symmetric(horizontal: 16),
childAspectRatio: 0.85, gridDelegate:
crossAxisCount: 3, const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: 30.0, childAspectRatio: 0.85,
mainAxisSpacing: 30.0, crossAxisCount: 3,
), crossAxisSpacing: 30.0,
itemBuilder: (context, index) { mainAxisSpacing: 30.0,
if (index == 0) { ),
return AddData( itemBuilder: (context, index) {
title: 'Edit Perhitungan', if (index == 0) {
onPressed: () => onAddDataTap(serviceChargeValue, taxModel.value), return AddData(
title: 'Edit Perhitungan',
onPressed: () => onAddDataTap(
serviceChargeValue, taxModel.value),
);
}
final item = items.firstWhere(
(element) => element.type.isLayanan);
return ManageTaxCard(
data: item,
onEditTap: () => onEditTap(
item, serviceChargeValue, taxModel.value),
); );
} },
final item = items.firstWhere((element) => element.type.isLayanan); ),
return ManageTaxCard(
data: item,
onEditTap: () => onEditTap(item, serviceChargeValue, taxModel.value),
);
},
), ),
),
// PAJAK TAB // PAJAK TAB
SizedBox( SizedBox(
child: GridView.builder( child: GridView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: 2, // Add button + 1 tax item itemCount: 2, // Add button + 1 tax item
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( padding: const EdgeInsets.symmetric(horizontal: 16),
childAspectRatio: 0.85, gridDelegate:
crossAxisCount: 3, const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: 30.0, childAspectRatio: 0.85,
mainAxisSpacing: 30.0, crossAxisCount: 3,
), crossAxisSpacing: 30.0,
itemBuilder: (context, index) { mainAxisSpacing: 30.0,
if (index == 0) { ),
return AddData( itemBuilder: (context, index) {
title: 'Edit Perhitungan', if (index == 0) {
onPressed: () => onAddDataTap(serviceChargeValue, taxModel.value), return AddData(
title: 'Edit Perhitungan',
onPressed: () => onAddDataTap(
serviceChargeValue, taxModel.value),
);
}
final item = items.firstWhere(
(element) => element.type.isPajak);
return ManageTaxCard(
data: item,
onEditTap: () => onEditTap(
item, serviceChargeValue, taxModel.value),
); );
} },
final item = items.firstWhere((element) => element.type.isPajak); ),
return ManageTaxCard(
data: item,
onEditTap: () => onEditTap(item, serviceChargeValue, taxModel.value),
);
},
), ),
), ],
], );
); },
}, );
); },
}, ),
), ),
], ),
), ],
); );
} }
} }

View File

@ -3,8 +3,6 @@ import 'package:flutter/material.dart';
import '../../../core/components/spaces.dart'; import '../../../core/components/spaces.dart';
import '../../../core/constants/colors.dart'; import '../../../core/constants/colors.dart';
class AddData extends StatelessWidget { class AddData extends StatelessWidget {
final String title; final String title;
final VoidCallback onPressed; final VoidCallback onPressed;
@ -21,18 +19,25 @@ class AddData extends StatelessWidget {
onTap: onPressed, onTap: onPressed,
child: Container( child: Container(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
decoration: ShapeDecoration( decoration: BoxDecoration(
shape: RoundedRectangleBorder( color: AppColors.white,
side: const BorderSide(width: 1, color: AppColors.card), borderRadius: BorderRadius.circular(8.0),
borderRadius: BorderRadius.circular(19),
),
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const Icon( Container(
Icons.add, width: 56.0,
color: AppColors.primary, height: 56.0,
padding: const EdgeInsets.all(12.0),
decoration: BoxDecoration(
color: AppColors.primary.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.add,
color: AppColors.primary,
),
), ),
const SpaceHeight(8.0), const SpaceHeight(8.0),
Text( Text(

View File

@ -18,11 +18,9 @@ class ManageTaxCard extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
decoration: ShapeDecoration( decoration: BoxDecoration(
shape: RoundedRectangleBorder( color: AppColors.white,
side: const BorderSide(width: 1, color: AppColors.card), borderRadius: BorderRadius.circular(8.0),
borderRadius: BorderRadius.circular(19),
),
), ),
child: Stack( child: Stack(
children: [ children: [
@ -36,7 +34,7 @@ class ManageTaxCard extends StatelessWidget {
margin: const EdgeInsets.only(top: 30.0), margin: const EdgeInsets.only(top: 30.0),
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: AppColors.disabled.withOpacity(0.4), color: AppColors.primary.withOpacity(0.1),
), ),
child: Text( child: Text(
'${data.value}%', '${data.value}%',
@ -48,23 +46,12 @@ class ManageTaxCard extends StatelessWidget {
), ),
const Spacer(), const Spacer(),
Center( Center(
child: RichText( child: Text(
text: TextSpan( data.type.name,
text: 'Nama Promo : ', style: const TextStyle(
children: [ fontSize: 16,
TextSpan( fontWeight: FontWeight.w600,
text: data.type.name, color: AppColors.black,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
],
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: AppColors.black,
),
), ),
), ),
), ),