import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../../application/analytic/exclusive_summary_loader/exclusive_summary_loader_bloc.dart'; import '../../../../application/auth/auth_bloc.dart'; import '../../../../application/outlet/selected_outlet/selected_outlet_bloc.dart'; import '../../../../common/extension/extension.dart'; import '../../../../common/painter/wave_painter.dart'; import '../../../../common/theme/theme.dart'; import '../../../components/spacer/spacer.dart'; import 'header_date_filter.dart'; import 'header_outlet_selector.dart'; import 'header_summary_slider.dart'; import 'header_top_bar.dart'; class HomeHeader extends StatefulWidget { final int totalRevenue; const HomeHeader({super.key, required this.totalRevenue}); @override State createState() => _HomeHeaderState(); } class _HomeHeaderState extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _fadeInAnimation; late Animation _slideAnimation; /// 0 = Hari Ini, 1 = MTD (Bulan) int _selectedDateFilter = 0; bool _isValueVisible = true; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 1200), vsync: this, ); _fadeInAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _animationController, curve: const Interval(0.0, 0.6, curve: Curves.easeOut), ), ); _slideAnimation = Tween(begin: const Offset(0, 0.3), end: Offset.zero).animate( CurvedAnimation( parent: _animationController, curve: const Interval(0.2, 0.8, curve: Curves.easeOutCubic), ), ); _animationController.forward(); WidgetsBinding.instance.addPostFrameCallback((_) { _fetchSummary(); }); } void _fetchSummary() { final now = DateTime.now(); DateTime dateFrom; DateTime dateTo; if (_selectedDateFilter == 0) { dateFrom = DateTime(now.year, now.month, now.day); dateTo = DateTime(now.year, now.month, now.day); } else { // MTD: tanggal 1 s/d hari ini dateFrom = DateTime(now.year, now.month, 1); dateTo = DateTime(now.year, now.month, now.day); } context.read() ..add(ExclusiveSummaryLoaderEvent.rangeDateChanged(dateFrom, dateTo)) ..add(const ExclusiveSummaryLoaderEvent.fetched()); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return BlocListener( listenWhen: (prev, curr) => prev.selectedOutletId != curr.selectedOutletId, listener: (context, state) => _fetchSummary(), child: BlocBuilder( builder: (context, authState) { return Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppColor.primary, AppColor.primary.withOpacity(0.9), AppColor.primaryLight.withOpacity(0.85), ], begin: Alignment.topLeft, end: Alignment.bottomRight, stops: const [0.0, 0.7, 1.0], ), ), child: Stack( children: [ // Decorative circles _buildDecorations(), // Wave pattern Positioned.fill( child: CustomPaint( painter: WavePainter( animation: 0.0, color: AppColor.white.withOpacity(0.08), ), ), ), // Main content SafeArea( child: Padding( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ // Top bar SlideTransition( position: _slideAnimation, child: FadeTransition( opacity: _fadeInAnimation, child: HeaderTopBar(user: authState.user), ), ), const SpaceHeight(16), // Outlet selector SlideTransition( position: _slideAnimation, child: FadeTransition( opacity: _fadeInAnimation, child: const HeaderOutletSelector(), ), ), const SpaceHeight(12), // Date filter tabs FadeTransition( opacity: _fadeInAnimation, child: HeaderDateFilter( selectedIndex: _selectedDateFilter, onChanged: (index) { setState(() => _selectedDateFilter = index); _fetchSummary(); }, ), ), const SpaceHeight(12), // Ringkasan label FadeTransition( opacity: _fadeInAnimation, child: _buildRingkasanLabel(), ), const SpaceHeight(12), // Sliding summary cards FadeTransition( opacity: _fadeInAnimation, child: HeaderSummarySlider( isValueVisible: _isValueVisible, ), ), ], ), ), ), ], ), ); }, ), ); } Widget _buildDecorations() { return Stack( children: [ Positioned( top: -50, right: -50, child: Container( width: 150, height: 150, decoration: BoxDecoration( shape: BoxShape.circle, color: AppColor.white.withOpacity(0.10), ), ), ), Positioned( top: 80, right: -20, child: Container( width: 80, height: 80, decoration: BoxDecoration( shape: BoxShape.circle, color: AppColor.white.withOpacity(0.05), ), ), ), Positioned( top: 60, left: -30, child: Container( width: 100, height: 100, decoration: BoxDecoration( shape: BoxShape.circle, color: AppColor.white.withOpacity(0.03), ), ), ), ], ); } Widget _buildRingkasanLabel() { final now = DateTime.now(); final dateLabel = _selectedDateFilter == 0 ? '${context.lang.summary_today} · ${now.day} ${_monthName(now.month)} ${now.year}' : '${context.lang.summary_mtd} · 1 - ${now.day} ${_monthName(now.month)} ${now.year}'; return Row( children: [ Expanded( child: Text( dateLabel, style: AppStyle.sm.copyWith( color: AppColor.white.withOpacity(0.9), fontWeight: FontWeight.w600, ), ), ), GestureDetector( onTap: () { setState(() => _isValueVisible = !_isValueVisible); }, child: Icon( _isValueVisible ? Icons.visibility_outlined : Icons.visibility_off_outlined, color: AppColor.white.withOpacity(0.7), size: 20, ), ), ], ); } String _monthName(int month) { const months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des', ]; return months[month - 1]; } }