Efril 843c11b200
Some checks are pending
Build & Deploy iOS to TestFlight / build-and-deploy (push) Waiting to run
feat: update stock ui
2026-06-24 10:28:13 +07:00

213 lines
6.6 KiB
Dart

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../application/analytic/inventory_analytic_loader/inventory_analytic_loader_bloc.dart';
import '../../../common/theme/theme.dart';
import '../../../injection.dart';
import '../../components/spacer/spacer.dart';
import 'widgets/inventory_header.dart';
import 'widgets/inventory_stock_report.dart';
@RoutePage()
class InventoryPage extends StatefulWidget implements AutoRouteWrapper {
const InventoryPage({super.key});
@override
State<InventoryPage> createState() => _InventoryPageState();
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (_) =>
getIt<InventoryAnalyticLoaderBloc>()
..add(InventoryAnalyticLoaderEvent.fetched()),
child: this,
);
}
class _InventoryPageState extends State<InventoryPage>
with SingleTickerProviderStateMixin {
late AnimationController _fadeController;
late Animation<double> _fadeAnimation;
int _selectedTabIndex = 0;
@override
void initState() {
super.initState();
_fadeController = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this,
);
_fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(parent: _fadeController, curve: Curves.easeIn));
_fadeController.forward();
}
@override
void dispose() {
_fadeController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.background,
body:
BlocListener<
InventoryAnalyticLoaderBloc,
InventoryAnalyticLoaderState
>(
listenWhen: (previous, current) =>
previous.dateFrom != current.dateFrom ||
previous.dateTo != current.dateTo,
listener: (context, state) {
context.read<InventoryAnalyticLoaderBloc>().add(
InventoryAnalyticLoaderEvent.fetched(),
);
},
child:
BlocBuilder<
InventoryAnalyticLoaderBloc,
InventoryAnalyticLoaderState
>(
builder: (context, state) {
return CustomScrollView(
slivers: [
// Header with gradient background, tabs, and summary
SliverToBoxAdapter(
child: FadeTransition(
opacity: _fadeAnimation,
child: InventoryHeader(
state: state,
selectedTabIndex: _selectedTabIndex,
onTabChanged: (index) {
setState(() {
_selectedTabIndex = index;
});
},
onDateRangeChanged: (startDate, endDate) {
_onDateRangeChanged(
context,
startDate,
endDate,
);
},
),
),
),
// Stock Report Table
SliverToBoxAdapter(
child: FadeTransition(
opacity: _fadeAnimation,
child: state.isFetching
? _buildLoadingReport()
: InventoryStockReport(
inventoryAnalytic: state.inventoryAnalytic,
selectedTabIndex: _selectedTabIndex,
),
),
),
// Bottom spacing
const SliverToBoxAdapter(child: SpaceHeight(100)),
],
);
},
),
),
);
}
Widget _buildLoadingReport() {
return Container(
margin: const EdgeInsets.all(16),
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: AppColor.textLight.withOpacity(0.08),
spreadRadius: 1,
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
children: List.generate(
5,
(index) => Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
Expanded(
flex: 4,
child: Container(
height: 14,
decoration: BoxDecoration(
color: AppColor.borderLight,
borderRadius: BorderRadius.circular(4),
),
),
),
const SpaceWidth(12),
Expanded(
flex: 2,
child: Container(
height: 14,
decoration: BoxDecoration(
color: AppColor.borderLight,
borderRadius: BorderRadius.circular(4),
),
),
),
const SpaceWidth(12),
Expanded(
flex: 2,
child: Container(
height: 14,
decoration: BoxDecoration(
color: AppColor.borderLight,
borderRadius: BorderRadius.circular(4),
),
),
),
const SpaceWidth(12),
Expanded(
flex: 2,
child: Container(
height: 14,
decoration: BoxDecoration(
color: AppColor.borderLight,
borderRadius: BorderRadius.circular(4),
),
),
),
],
),
),
),
),
);
}
void _onDateRangeChanged(
BuildContext context,
DateTime startDate,
DateTime endDate,
) {
context.read<InventoryAnalyticLoaderBloc>().add(
InventoryAnalyticLoaderEvent.rangeDateChanged(startDate, endDate),
);
}
}