diff --git a/lib/presentation/success/pages/success_order_page.dart b/lib/presentation/success/pages/success_order_page.dart index dda2b69..ea9ab59 100644 --- a/lib/presentation/success/pages/success_order_page.dart +++ b/lib/presentation/success/pages/success_order_page.dart @@ -1,5 +1,3 @@ -import 'package:enaklo_pos/core/components/components.dart'; -import 'package:enaklo_pos/core/components/dashed_divider.dart'; 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'; @@ -10,186 +8,1189 @@ 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 StatelessWidget { +class SuccessOrderPage extends StatefulWidget { final List productQuantity; final Order order; const SuccessOrderPage( {super.key, required this.order, required this.productQuantity}); + @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: Center( + body: SafeArea( child: Container( - width: context.deviceWidth * 0.4, - height: context.deviceHeight * 0.8, decoration: BoxDecoration( - color: AppColors.white, - borderRadius: const BorderRadius.all(Radius.circular(12.0)), + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + AppColors.primary.withOpacity(0.05), + AppColors.background, + AppColors.background, + ], + ), ), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - Text( - 'Pesanan!', - style: const TextStyle( - fontSize: 18, fontWeight: FontWeight.bold), - ), - Text('Pesanan berhasil ', - style: const TextStyle(fontSize: 14)), - ], - ), - ), - DashedDivider( - color: AppColors.grey, - ), - SpaceHeight(24), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Text( - order.metadata?['customer_name'] ?? "-", - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.primary, - ), - textAlign: TextAlign.center, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ), - Padding( - padding: const EdgeInsets.all(16.0).copyWith(top: 24), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'No. Pesanan', - ), - Text( - order.orderNumber ?? "-", - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - SpaceHeight(4), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'No. Meja', - ), - Text( - order.tableNumber ?? "-", - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - SpaceHeight(4), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Waktu', - ), - Text( - (order.createdAt ?? DateTime.now()) - .toFormattedDate3(), - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - ], - ), - ), - Spacer(), - DashedDivider( - color: AppColors.grey, - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Status Pembayaran', - ), - Text( - 'Lunas', - style: const TextStyle( - fontWeight: FontWeight.bold, - color: Colors.green, - ), - ), - ], - ), - ), - DashedDivider( - color: AppColors.grey, - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Total Pembayaran', - ), - Text( - (order.totalAmount ?? 0).toString().currencyFormatRpV2, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - ), - DashedDivider( - color: AppColors.grey, - ), - Spacer(), - Padding( - padding: const EdgeInsets.all(16.0), + 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( - child: Button.outlined( - onPressed: () { - context.push(DashboardPage()); - }, - label: 'Kembali', - height: 44, - ), + flex: 35, + child: _buildLeftPanel(), ), - SpaceWidth(12), + + const SizedBox(width: 16), + + // Right Panel - Order Details Expanded( - child: Button.filled( - onPressed: () async { - onPrint( - context, - productQuantity: productQuantity, - order: order, - ); - }, - label: 'Cetak', - icon: Icon( - Icons.print, - color: AppColors.white, - ), - height: 44, - ), + 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; + + 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) + .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 { + 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, + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + } }