Some checks are pending
Build & Deploy iOS to TestFlight / build-and-deploy (push) Waiting to run
214 lines
7.0 KiB
Dart
214 lines
7.0 KiB
Dart
import 'package:auto_route/auto_route.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
import '../../../application/analytic/category_analytic_loader/category_analytic_loader_bloc.dart';
|
|
import '../../../application/analytic/payment_method_analytic_loader/payment_method_analytic_loader_bloc.dart';
|
|
import '../../../application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart';
|
|
import '../../../application/analytic/sales_loader/sales_loader_bloc.dart';
|
|
import '../../../common/theme/theme.dart';
|
|
import '../../../injection.dart';
|
|
import '../../components/spacer/spacer.dart';
|
|
import 'widgets/sales_category_card.dart';
|
|
import 'widgets/sales_header.dart';
|
|
import 'widgets/sales_payment_method_card.dart';
|
|
import 'widgets/sales_rincian_card.dart';
|
|
import 'widgets/sales_top_products_card.dart';
|
|
|
|
@RoutePage()
|
|
class SalesPage extends StatefulWidget implements AutoRouteWrapper {
|
|
const SalesPage({super.key});
|
|
|
|
@override
|
|
State<SalesPage> createState() => _SalesPageState();
|
|
|
|
@override
|
|
Widget wrappedRoute(BuildContext context) => MultiBlocProvider(
|
|
providers: [
|
|
BlocProvider(
|
|
create: (context) =>
|
|
getIt<SalesLoaderBloc>()..add(SalesLoaderEvent.fectched()),
|
|
),
|
|
BlocProvider(
|
|
create: (context) =>
|
|
getIt<PaymentMethodAnalyticLoaderBloc>()
|
|
..add(const PaymentMethodAnalyticLoaderEvent.fetched()),
|
|
),
|
|
BlocProvider(
|
|
create: (context) =>
|
|
getIt<CategoryAnalyticLoaderBloc>()
|
|
..add(const CategoryAnalyticLoaderEvent.fetched()),
|
|
),
|
|
BlocProvider(
|
|
create: (context) =>
|
|
getIt<ProductAnalyticLoaderBloc>()
|
|
..add(const ProductAnalyticLoaderEvent.fetched()),
|
|
),
|
|
],
|
|
child: this,
|
|
);
|
|
}
|
|
|
|
class _SalesPageState extends State<SalesPage>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _fadeController;
|
|
late Animation<double> _fadeAnimation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
_fadeController = AnimationController(
|
|
duration: const Duration(milliseconds: 600),
|
|
vsync: this,
|
|
);
|
|
_fadeAnimation = CurvedAnimation(
|
|
parent: _fadeController,
|
|
curve: Curves.easeOut,
|
|
);
|
|
|
|
Future.delayed(const Duration(milliseconds: 300), () {
|
|
_fadeController.forward();
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_fadeController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: AppColor.background,
|
|
body: BlocBuilder<SalesLoaderBloc, SalesLoaderState>(
|
|
builder: (context, salesState) {
|
|
return CustomScrollView(
|
|
slivers: [
|
|
// Header
|
|
SliverToBoxAdapter(
|
|
child: SalesHeader(
|
|
state: salesState,
|
|
onDateRangeChanged: (startDate, endDate) {
|
|
_onDateRangeChanged(context, startDate, endDate);
|
|
},
|
|
),
|
|
),
|
|
|
|
// Rincian Penjualan
|
|
SliverToBoxAdapter(
|
|
child: FadeTransition(
|
|
opacity: _fadeAnimation,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: SalesRincianCard(state: salesState),
|
|
),
|
|
),
|
|
),
|
|
|
|
// Metode Pembayaran
|
|
SliverToBoxAdapter(
|
|
child: FadeTransition(
|
|
opacity: _fadeAnimation,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child:
|
|
BlocBuilder<
|
|
PaymentMethodAnalyticLoaderBloc,
|
|
PaymentMethodAnalyticLoaderState
|
|
>(
|
|
builder: (context, paymentState) {
|
|
return SalesPaymentMethodCard(
|
|
paymentMethodAnalytic:
|
|
paymentState.paymentMethodAnalytic,
|
|
isFetching: paymentState.isFetching,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
|
|
// Penjualan per Kategori
|
|
SliverToBoxAdapter(
|
|
child: FadeTransition(
|
|
opacity: _fadeAnimation,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child:
|
|
BlocBuilder<
|
|
CategoryAnalyticLoaderBloc,
|
|
CategoryAnalyticLoaderState
|
|
>(
|
|
builder: (context, categoryState) {
|
|
return SalesCategoryCard(
|
|
categoryAnalytic: categoryState.categoryAnalytic,
|
|
isFetching: categoryState.isFetching,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
|
|
// Produk Terlaris
|
|
SliverToBoxAdapter(
|
|
child: FadeTransition(
|
|
opacity: _fadeAnimation,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child:
|
|
BlocBuilder<
|
|
ProductAnalyticLoaderBloc,
|
|
ProductAnalyticLoaderState
|
|
>(
|
|
builder: (context, productState) {
|
|
return SalesTopProductsCard(
|
|
productAnalytic: productState.productAnalytic,
|
|
isFetching: productState.isFetching,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
|
|
// Bottom Padding
|
|
const SliverToBoxAdapter(child: SpaceHeight(32)),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
void _onDateRangeChanged(
|
|
BuildContext context,
|
|
DateTime startDate,
|
|
DateTime endDate,
|
|
) {
|
|
// Update sales
|
|
context.read<SalesLoaderBloc>()
|
|
..add(SalesLoaderEvent.rangeDateChanged(startDate, endDate))
|
|
..add(SalesLoaderEvent.fectched());
|
|
|
|
// Update payment method
|
|
context.read<PaymentMethodAnalyticLoaderBloc>()
|
|
..add(
|
|
PaymentMethodAnalyticLoaderEvent.rangeDateChanged(startDate, endDate),
|
|
)
|
|
..add(const PaymentMethodAnalyticLoaderEvent.fetched());
|
|
|
|
// Update category
|
|
context.read<CategoryAnalyticLoaderBloc>()
|
|
..add(CategoryAnalyticLoaderEvent.rangeDateChanged(startDate, endDate))
|
|
..add(const CategoryAnalyticLoaderEvent.fetched());
|
|
|
|
// Update product
|
|
context.read<ProductAnalyticLoaderBloc>()
|
|
..add(ProductAnalyticLoaderEvent.rangeDateChanged(startDate, endDate))
|
|
..add(const ProductAnalyticLoaderEvent.fetched());
|
|
}
|
|
}
|