feat: sales range date

This commit is contained in:
efrilm
2025-08-18 16:43:07 +07:00
parent 2d25e15380
commit 1f6e5e9a2b
10 changed files with 1286 additions and 190 deletions
+110 -159
View File
@@ -10,6 +10,7 @@ import '../../../common/theme/theme.dart';
import '../../../domain/analytic/analytic.dart';
import '../../../injection.dart';
import '../../components/appbar/appbar.dart';
import '../../components/field/date_range_picker_field.dart';
import '../../components/spacer/spacer.dart';
import 'widgets/summary_card.dart';
@@ -79,143 +80,125 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.background,
body: BlocBuilder<SalesLoaderBloc, SalesLoaderState>(
builder: (context, state) {
return CustomScrollView(
slivers: [
// App Bar
SliverAppBar(
expandedHeight: 120,
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
flexibleSpace: CustomAppBar(title: 'Penjualan'),
),
// Date Range Header
SliverToBoxAdapter(
child: SlideTransition(
position: slideAnimation,
child: FadeTransition(
opacity: fadeAnimation,
child: state.isFetching
? _buildDateRangeShimmer()
: _buildDateRangeHeader(),
),
body: BlocListener<SalesLoaderBloc, SalesLoaderState>(
listenWhen: (previous, current) =>
previous.dateFrom != current.dateFrom &&
previous.dateTo != current.dateTo,
listener: (context, state) {
context.read<SalesLoaderBloc>().add(SalesLoaderEvent.fectched());
},
child: BlocBuilder<SalesLoaderBloc, SalesLoaderState>(
builder: (context, state) {
return CustomScrollView(
slivers: [
// App Bar
SliverAppBar(
expandedHeight: 120,
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
flexibleSpace: CustomAppBar(title: 'Penjualan'),
),
),
// Summary Cards
SliverToBoxAdapter(
child: SlideTransition(
position: slideAnimation,
child: FadeTransition(
opacity: fadeAnimation,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Summary',
style: AppStyle.xxl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
const SpaceHeight(16),
state.isFetching
? _buildSummaryShimmer()
: _buildSummaryCards(state),
],
),
),
),
),
),
// Net Sales Card
SliverToBoxAdapter(
child: SlideTransition(
position: slideAnimation,
child: FadeTransition(
opacity: fadeAnimation,
child: state.isFetching
? _buildNetSalesShimmer()
: _buildNetSalesCard(state),
),
),
),
// Daily Sales Section Header
SliverToBoxAdapter(
child: SlideTransition(
position: slideAnimation,
child: FadeTransition(
opacity: fadeAnimation,
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
child: Text(
'Daily Breakdown',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
// Date Range Header
SliverToBoxAdapter(
child: SlideTransition(
position: slideAnimation,
child: FadeTransition(
opacity: fadeAnimation,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: DateRangePickerField(
maxDate: DateTime.now(),
startDate: state.dateFrom,
endDate: state.dateTo,
onChanged: (startDate, endDate) {
context.read<SalesLoaderBloc>().add(
SalesLoaderEvent.rangeDateChanged(
startDate!,
endDate!,
),
);
},
),
),
),
),
),
),
// Daily Sales List
state.isFetching
? _buildDailySalesShimmer()
: _buildDailySalesList(state),
// Bottom Padding
const SliverToBoxAdapter(child: SpaceHeight(32)),
],
);
},
),
);
}
// Shimmer Components
Widget _buildDateRangeShimmer() {
return Container(
margin: const EdgeInsets.all(16),
child: Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
// Summary Cards
SliverToBoxAdapter(
child: SlideTransition(
position: slideAnimation,
child: FadeTransition(
opacity: fadeAnimation,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Summary',
style: AppStyle.xxl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
const SpaceHeight(16),
state.isFetching
? _buildSummaryShimmer()
: _buildSummaryCards(state),
],
),
),
),
),
),
),
SpaceWidth(8),
Container(
width: 150,
height: 16,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
// Net Sales Card
SliverToBoxAdapter(
child: SlideTransition(
position: slideAnimation,
child: FadeTransition(
opacity: fadeAnimation,
child: state.isFetching
? _buildNetSalesShimmer()
: _buildNetSalesCard(state),
),
),
),
),
],
),
// Daily Sales Section Header
SliverToBoxAdapter(
child: SlideTransition(
position: slideAnimation,
child: FadeTransition(
opacity: fadeAnimation,
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
child: Text(
'Daily Breakdown',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
),
),
),
),
// Daily Sales List
state.isFetching
? _buildDailySalesShimmer()
: _buildDailySalesList(state),
// Bottom Padding
const SliverToBoxAdapter(child: SpaceHeight(32)),
],
);
},
),
),
);
@@ -415,38 +398,6 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
);
}
// Original Components (preserved)
Widget _buildDateRangeHeader() {
return Container(
margin: const EdgeInsets.all(16),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Row(
children: [
Icon(Icons.date_range, color: AppColor.primary, size: 20),
SpaceWidth(8),
Text(
'Aug 1 - Aug 15, 2025',
style: AppStyle.md.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w500,
),
),
],
),
);
}
Widget _buildSummaryCards(SalesLoaderState state) {
return Column(
children: [