feat: sales range date
This commit is contained in:
@@ -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: [
|
||||
|
||||
Reference in New Issue
Block a user