import 'package:enaklo_pos/core/constants/colors.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/date_time_ext.dart'; import 'package:enaklo_pos/core/extensions/string_ext.dart'; import 'package:enaklo_pos/core/function/app_function.dart'; import 'package:enaklo_pos/data/models/response/order_response_model.dart'; import 'package:enaklo_pos/presentation/home/models/product_quantity.dart'; import 'package:enaklo_pos/presentation/home/pages/dashboard_page.dart'; import 'package:flutter/material.dart'; class SuccessOrderPage extends StatefulWidget { final List productQuantity; final Order order; final String paymentMethod; final int nominalBayar; final int taxPercentage; const SuccessOrderPage({ super.key, required this.order, required this.productQuantity, required this.paymentMethod, required this.nominalBayar, required this.taxPercentage, }); @override State createState() => _SuccessOrderPageState(); } class _SuccessOrderPageState extends State with TickerProviderStateMixin { late AnimationController _mainController; late AnimationController _successController; late AnimationController _cardController; late AnimationController _floatingController; late Animation _fadeInAnimation; late Animation _scaleAnimation; late Animation _successIconAnimation; late Animation _slideUpAnimation; late Animation _floatingAnimation; late Animation _shimmerAnimation; @override void initState() { super.initState(); _mainController = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this, ); _successController = AnimationController( duration: const Duration(milliseconds: 1500), vsync: this, ); _cardController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); _floatingController = AnimationController( duration: const Duration(seconds: 3), vsync: this, )..repeat(reverse: true); _fadeInAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _mainController, curve: const Interval(0.0, 0.6, curve: Curves.easeOut), )); _scaleAnimation = Tween( begin: 0.8, end: 1.0, ).animate(CurvedAnimation( parent: _mainController, curve: const Interval(0.2, 0.8, curve: Curves.elasticOut), )); _successIconAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _successController, curve: Curves.elasticOut, )); _slideUpAnimation = Tween( begin: const Offset(0.0, 0.3), end: Offset.zero, ).animate(CurvedAnimation( parent: _cardController, curve: Curves.easeOutCubic, )); _floatingAnimation = Tween( begin: -5.0, end: 5.0, ).animate(CurvedAnimation( parent: _floatingController, curve: Curves.easeInOut, )); _shimmerAnimation = Tween( begin: -1.0, end: 2.0, ).animate(CurvedAnimation( parent: _mainController, curve: Curves.easeInOut, )); // Start animations with staggered delays _startAnimations(); } void _startAnimations() async { await Future.delayed(const Duration(milliseconds: 300)); _mainController.forward(); await Future.delayed(const Duration(milliseconds: 500)); _successController.forward(); await Future.delayed(const Duration(milliseconds: 700)); _cardController.forward(); } @override void dispose() { _mainController.dispose(); _successController.dispose(); _cardController.dispose(); _floatingController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.background, body: SafeArea( child: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ AppColors.primary.withOpacity(0.05), AppColors.background, AppColors.background, ], ), ), child: FadeTransition( opacity: _fadeInAnimation, child: ScaleTransition( scale: _scaleAnimation, child: Padding( padding: const EdgeInsets.all(24.0), child: Row( children: [ // Left Panel - Success Message & Order Info Expanded( flex: 35, child: _buildLeftPanel(), ), const SizedBox(width: 16), // Right Panel - Order Details Expanded( flex: 65, child: _buildRightPanel(), ), ], ), ), ), ), ), ), ); } Widget _buildLeftPanel() { return SlideTransition( position: _slideUpAnimation, child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( color: AppColors.primary.withOpacity(0.1), blurRadius: 30, offset: const Offset(0, 10), ), ], ), child: Column( children: [ // Success Header with Glassmorphism Effect Container( width: double.infinity, padding: const EdgeInsets.all(32.0), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ AppColors.primary.withOpacity(0.1), AppColors.primary.withOpacity(0.05), ], ), borderRadius: const BorderRadius.vertical( top: Radius.circular(24), ), ), child: Column( children: [ // Animated Success Icon with Floating Effect AnimatedBuilder( animation: _floatingAnimation, builder: (context, child) { return Transform.translate( offset: Offset(0, _floatingAnimation.value), child: ScaleTransition( scale: _successIconAnimation, child: Container( padding: const EdgeInsets.all(20.0), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ AppColors.primary, AppColors.primary.withOpacity(0.8), ], ), shape: BoxShape.circle, boxShadow: [ BoxShadow( color: AppColors.primary.withOpacity(0.3), blurRadius: 20, offset: const Offset(0, 10), ), ], ), child: const Icon( Icons.check_rounded, size: 48, color: Colors.white, ), ), ), ); }, ), const SizedBox(height: 24), // Success Title with Shimmer Effect FadeTransition( opacity: _fadeInAnimation, child: ShaderMask( shaderCallback: (bounds) { return LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: const [ AppColors.primary, Colors.amber, AppColors.primary, ], stops: [ _shimmerAnimation.value - 1, _shimmerAnimation.value, _shimmerAnimation.value + 1, ], ).createShader(bounds); }, child: const Text( 'Pesanan Berhasil!', style: TextStyle( fontSize: 26, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), const SizedBox(height: 12), FadeTransition( opacity: _fadeInAnimation, child: Container( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(20), ), child: const Text( 'Pesanan telah diterima dan sedang diproses', style: TextStyle( fontSize: 14, color: AppColors.primary, fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), ), ), ], ), ), // Order Information Section Expanded( child: Padding( padding: const EdgeInsets.all(24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildSectionTitle('Informasi Pesanan'), const SizedBox(height: 24), // Customer Card with Gradient Background _buildInfoCard( icon: Icons.person_outline_rounded, title: 'Nama Pelanggan', value: widget.order.metadata?['customer_name'] ?? "-", gradient: [ Colors.blue.withOpacity(0.1), Colors.purple.withOpacity(0.1), ], ), const SizedBox(height: 16), // Order Details Grid Expanded( child: Column( children: [ _buildInfoRow( icon: Icons.receipt_long_outlined, label: 'No. Pesanan', value: widget.order.orderNumber ?? "-", delay: 0.3, ), const SizedBox(height: 12), _buildInfoRow( icon: Icons.table_restaurant_outlined, label: 'No. Meja', value: widget.order.tableNumber ?? "-", delay: 0.4, ), const SizedBox(height: 12), _buildInfoRow( icon: Icons.access_time_rounded, label: 'Waktu', value: (widget.order.createdAt ?? DateTime.now()) .toFormattedDate3(), delay: 0.5, ), const SizedBox(height: 12), _buildInfoRow( icon: Icons.check_circle_outline, label: 'Status Pembayaran', value: 'Lunas', delay: 0.6, valueColor: Colors.green, showBadge: true, ), ], ), ), ], ), ), ), // Total and Action Buttons _buildBottomSection(), ], ), ), ); } Widget _buildRightPanel() { return SlideTransition( position: _slideUpAnimation, child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.08), blurRadius: 30, offset: const Offset(0, 10), ), ], ), child: Column( children: [ // Header with Modern Design Container( width: double.infinity, padding: const EdgeInsets.all(24.0), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ AppColors.background, Colors.grey.shade50, ], ), borderRadius: const BorderRadius.vertical( top: Radius.circular(24), ), ), child: Row( children: [ ScaleTransition( scale: _successIconAnimation, child: Container( padding: const EdgeInsets.all(12.0), decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppColors.primary.withOpacity(0.2), AppColors.primary.withOpacity(0.1), ], ), borderRadius: BorderRadius.circular(16.0), ), child: Icon( Icons.receipt_long_rounded, color: AppColors.primary, size: 28, ), ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ FadeTransition( opacity: _fadeInAnimation, child: const Text( 'Detail Pesanan', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 4), FadeTransition( opacity: _fadeInAnimation, child: Text( 'Ringkasan item yang dipesan', style: TextStyle( fontSize: 14, color: Colors.grey.shade600, ), ), ), ], ), ), ScaleTransition( scale: _scaleAnimation, child: Container( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 10), decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppColors.primary, AppColors.primary.withOpacity(0.8), ], ), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: AppColors.primary.withOpacity(0.3), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Text( '${widget.productQuantity.length} Items', style: const TextStyle( fontSize: 13, color: Colors.white, fontWeight: FontWeight.bold, ), ), ), ), ], ), ), // Enhanced Product List Expanded( child: ListView.separated( padding: const EdgeInsets.all(24.0), itemCount: widget.productQuantity.length, separatorBuilder: (context, index) => const SizedBox(height: 12), itemBuilder: (context, index) { return _buildProductCard(index); }, ), ), // Enhanced Summary Footer _buildSummaryFooter(), ], ), ), ); } Widget _buildProductCard(int index) { final item = widget.productQuantity[index]; final totalPrice = (item.product.price ?? 0) * item.quantity + (item.variant?.priceModifier ?? 0); return TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: Duration(milliseconds: 600 + (index * 100)), curve: Curves.easeOutCubic, builder: (context, animation, child) { return Transform.translate( offset: Offset(0, 20 * (1 - animation)), child: Opacity( opacity: animation, child: Container( padding: const EdgeInsets.all(16.0), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ Colors.grey.shade50, Colors.white, ], ), borderRadius: BorderRadius.circular(16.0), border: Border.all( color: Colors.grey.withOpacity(0.1), width: 1, ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Row( children: [ // Enhanced Product Image Hero( tag: 'product_${index}', child: Container( width: 70, height: 70, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ AppColors.primary.withOpacity(0.2), AppColors.primary.withOpacity(0.1), ], ), borderRadius: BorderRadius.circular(16.0), boxShadow: [ BoxShadow( color: AppColors.primary.withOpacity(0.2), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Icon( Icons.restaurant_rounded, color: AppColors.primary, size: 28, ), ), ), const SizedBox(width: 16), // Product Details Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.product.name ?? "-", style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 6), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: BorderRadius.circular(8), ), child: Text( ((item.product.price ?? 0) + (item.variant?.priceModifier ?? 0)) .toString() .currencyFormatRpV2, style: TextStyle( fontSize: 14, color: Colors.grey.shade700, fontWeight: FontWeight.w500, ), ), ), ], ), ), const SizedBox(width: 16), // Quantity and Total Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 8), decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppColors.primary, AppColors.primary.withOpacity(0.8), ], ), borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: AppColors.primary.withOpacity(0.3), blurRadius: 6, offset: const Offset(0, 2), ), ], ), child: Text( '${item.quantity}x', style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), const SizedBox(height: 8), Text( totalPrice.toString().currencyFormatRpV2, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: AppColors.primary, ), ), ], ), ], ), ), ), ); }, ); } Widget _buildSectionTitle(String title) { return FadeTransition( opacity: _fadeInAnimation, child: Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), ); } Widget _buildInfoCard({ required IconData icon, required String title, required String value, required List gradient, }) { return ScaleTransition( scale: _scaleAnimation, child: Container( width: double.infinity, padding: const EdgeInsets.all(20.0), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: gradient, ), borderRadius: BorderRadius.circular(16.0), border: Border.all( color: Colors.white.withOpacity(0.3), width: 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( icon, size: 20, color: AppColors.primary, ), const SizedBox(width: 8), Text( title, style: TextStyle( fontSize: 12, color: Colors.grey.shade600, fontWeight: FontWeight.w500, ), ), ], ), const SizedBox(height: 8), Text( value, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColors.primary, ), ), ], ), ), ); } Widget _buildInfoRow({ required IconData icon, required String label, required String value, required double delay, Color? valueColor, bool showBadge = false, }) { return TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: Duration(milliseconds: (800 + delay * 1000).round()), curve: Curves.easeOutCubic, builder: (context, animation, child) { return Transform.translate( offset: Offset(0, 10 * (1 - animation)), child: Opacity( opacity: animation, child: Row( children: [ Icon( icon, size: 18, color: Colors.grey.shade600, ), const SizedBox(width: 12), Expanded( child: Text( label, style: TextStyle( fontSize: 14, color: Colors.grey.shade600, ), ), ), if (showBadge && valueColor != null) Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: valueColor.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.check_circle, size: 14, color: valueColor, ), const SizedBox(width: 4), Text( value, style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: valueColor, ), ), ], ), ) else Text( value, style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: valueColor ?? Colors.black87, ), ), ], ), ), ); }, ); } Widget _buildBottomSection() { return Container( width: double.infinity, padding: const EdgeInsets.all(24.0), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.grey.shade50, Colors.white, ], ), borderRadius: const BorderRadius.vertical( bottom: Radius.circular(24), ), ), child: Column( children: [ // Total Amount with Enhanced Styling ScaleTransition( scale: _scaleAnimation, child: Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ AppColors.primary.withOpacity(0.1), AppColors.primary.withOpacity(0.05), ], ), borderRadius: BorderRadius.circular(16), border: Border.all( color: AppColors.primary.withOpacity(0.2), width: 1, ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Total Pembayaran', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), Text( (widget.order.totalAmount ?? 0) .toString() .currencyFormatRpV2, style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: AppColors.primary, ), ), ], ), ), ), const SizedBox(height: 24), // Action Buttons with Modern Design Row( children: [ Expanded( child: TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 800), curve: Curves.easeOutCubic, builder: (context, animation, child) { return Transform.scale( scale: animation, child: Container( height: 50, decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), border: Border.all( color: AppColors.primary.withOpacity(0.3), width: 2, ), ), child: Material( color: Colors.transparent, borderRadius: BorderRadius.circular(14), child: InkWell( borderRadius: BorderRadius.circular(14), onTap: () { context.push(DashboardPage()); }, child: const Center( child: Text( 'Kembali ke Beranda', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: AppColors.primary, ), ), ), ), ), ), ); }, ), ), const SizedBox(width: 16), Expanded( child: TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 1000), curve: Curves.easeOutCubic, builder: (context, animation, child) { return Transform.scale( scale: animation, child: Container( height: 50, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ AppColors.primary, AppColors.primary.withOpacity(0.8), ], ), borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: AppColors.primary.withOpacity(0.3), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Material( color: Colors.transparent, borderRadius: BorderRadius.circular(16), child: InkWell( borderRadius: BorderRadius.circular(16), onTap: () async { onPrintRecipt( context, order: widget.order, paymentMethod: widget.paymentMethod, nominalBayar: widget.paymentMethod == "Cash" ? widget.nominalBayar : widget.order.totalAmount ?? 0, kembalian: widget.nominalBayar - (widget.order.totalAmount ?? 0), ); onPrint( context, productQuantity: widget.productQuantity, order: widget.order, ); }, child: const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.print_rounded, color: Colors.white, size: 20, ), SizedBox(width: 8), Text( 'Cetak Struk', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white, ), ), ], ), ), ), ), ); }, ), ), ], ), ], ), ); } Widget _buildSummaryFooter() { return SlideTransition( position: _slideUpAnimation, child: Container( width: double.infinity, padding: const EdgeInsets.all(24.0), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.grey.shade50, Colors.white, ], ), borderRadius: const BorderRadius.vertical( bottom: Radius.circular(24), ), ), child: Column( children: [ // Decorative Divider Container( height: 1, margin: const EdgeInsets.only(bottom: 20), decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.transparent, AppColors.primary.withOpacity(0.3), Colors.transparent, ], ), ), ), // Subtotal Row FadeTransition( opacity: _fadeInAnimation, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon( Icons.shopping_cart_outlined, size: 16, color: Colors.grey.shade600, ), const SizedBox(width: 8), Text( 'Subtotal (${widget.productQuantity.length} items)', style: TextStyle( fontSize: 14, color: Colors.grey.shade600, fontWeight: FontWeight.w500, ), ), ], ), Text( (widget.order.totalAmount ?? 0) .toString() .currencyFormatRpV2, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, ), ), ], ), ), const SizedBox(height: 16), // Total Payment Row with Enhanced Styling ScaleTransition( scale: _scaleAnimation, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ AppColors.primary.withOpacity(0.1), AppColors.primary.withOpacity(0.05), ], ), borderRadius: BorderRadius.circular(12), border: Border.all( color: AppColors.primary.withOpacity(0.2), width: 1, ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: AppColors.primary.withOpacity(0.2), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.payments_rounded, size: 16, color: AppColors.primary, ), ), const SizedBox(width: 12), const Text( 'Total Pembayaran', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ], ), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppColors.primary, AppColors.primary.withOpacity(0.8), ], ), borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( color: AppColors.primary.withOpacity(0.3), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Text( (widget.order.totalAmount ?? 0) .toString() .currencyFormatRpV2, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ], ), ), ), ], ), ), ); } }