import 'package:enaklo_pos/core/components/buttons.dart'; import 'package:enaklo_pos/core/components/spaces.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/int_ext.dart'; import 'package:enaklo_pos/presentation/home/pages/dashboard_page.dart'; import 'package:enaklo_pos/presentation/void/painter/pattern_painter.dart'; import 'package:flutter/material.dart'; import 'package:enaklo_pos/data/models/response/order_response_model.dart'; class SuccessVoidPage extends StatefulWidget { final Order voidedOrder; final String voidType; final int voidAmount; final List? voidedItems; final String voidReason; const SuccessVoidPage({ super.key, required this.voidedOrder, required this.voidType, required this.voidAmount, this.voidedItems, required this.voidReason, }); @override State createState() => _SuccessVoidPageState(); } class _SuccessVoidPageState extends State with TickerProviderStateMixin { final Color primaryColor = Color(0xFF36175E); late AnimationController _animationController; late Animation _scaleAnimation; late Animation _fadeAnimation; late Animation _slideAnimation; @override void initState() { super.initState(); _setupAnimations(); _startAnimations(); } void _setupAnimations() { _animationController = AnimationController( duration: Duration(milliseconds: 1500), vsync: this, ); _scaleAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _animationController, curve: Curves.elasticOut, )); _fadeAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _animationController, curve: Interval(0.3, 1.0, curve: Curves.easeInOut), )); _slideAnimation = Tween( begin: Offset(0, 0.5), end: Offset.zero, ).animate(CurvedAnimation( parent: _animationController, curve: Interval(0.5, 1.0, curve: Curves.easeOutCubic), )); } void _startAnimations() { _animationController.forward(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[50], body: Stack( children: [ _buildBackgroundPattern(), SafeArea( child: Padding( padding: EdgeInsets.all(24.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Left Panel - Success Animation & Message Flexible( flex: 2, child: _buildSuccessPanel(), ), SizedBox(width: 24), // Right Panel - Void Details (FIXED SCROLL) Flexible( flex: 3, child: _buildDetailsPanel(), ), ], ), ), ), // REMOVED: Confetti overlay yang mengganggu scroll ], ), ); } Widget _buildSuccessPanel() { return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 20, offset: Offset(0, 10), ), ], ), child: Padding( padding: EdgeInsets.all(32), child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ // Success Icon with Animation ScaleTransition( scale: _scaleAnimation, child: Container( width: 120, height: 120, decoration: BoxDecoration( gradient: LinearGradient( colors: [Colors.green.shade400, Colors.green.shade600], begin: Alignment.topLeft, end: Alignment.bottomRight, ), shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.green.withOpacity(0.3), blurRadius: 20, offset: Offset(0, 10), ), ], ), child: Icon( Icons.check_rounded, color: Colors.white, size: 60, ), ), ), SizedBox(height: 32), // Success Title FadeTransition( opacity: _fadeAnimation, child: Text( 'Void Berhasil!', style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, color: Colors.green.shade700, ), textAlign: TextAlign.center, ), ), SizedBox(height: 16), // Success Message SlideTransition( position: _slideAnimation, child: FadeTransition( opacity: _fadeAnimation, child: Text( widget.voidType == 'all' ? 'Seluruh pesanan telah dibatalkan dengan sukses' : 'Item terpilih telah dibatalkan dengan sukses', style: TextStyle( fontSize: 16, color: Colors.grey[600], height: 1.5, ), textAlign: TextAlign.center, ), ), ), SizedBox(height: 32), // Order Info Card SlideTransition( position: _slideAnimation, child: FadeTransition( opacity: _fadeAnimation, child: Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( color: primaryColor.withOpacity(0.1), borderRadius: BorderRadius.circular(16), border: Border.all(color: primaryColor.withOpacity(0.2)), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( children: [ Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: primaryColor.withOpacity(0.2), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.receipt_long, color: primaryColor, size: 20, ), ), SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Pesanan #${widget.voidedOrder.orderNumber}', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: primaryColor, ), overflow: TextOverflow.ellipsis, ), Text( 'Meja: ${widget.voidedOrder.tableNumber ?? 'N/A'}', style: TextStyle( fontSize: 12, color: Colors.grey[600], ), overflow: TextOverflow.ellipsis, ), ], ), ), ], ), if (widget.voidAmount > 0) ...[ SizedBox(height: 16), Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.red.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Jumlah Void:', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, ), ), Text( (widget.voidAmount).currencyFormatRpV2, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.red.shade700, ), ), ], ), ), ], ], ), ), ), ), ], ), ), ); } // FIXED: Panel kanan dengan scroll yang benar Widget _buildDetailsPanel() { return LayoutBuilder( builder: (context, constraints) { return Container( height: constraints.maxHeight, // PENTING: Gunakan height dari parent decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 20, offset: Offset(0, 10), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header - Fixed Container( padding: EdgeInsets.all(24), decoration: BoxDecoration( color: primaryColor.withOpacity(0.1), borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20), ), ), child: Row( children: [ Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: primaryColor.withOpacity(0.2), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.info_outline, color: primaryColor, size: 24, ), ), SizedBox(width: 12), Expanded( child: Text( 'Detail Void', style: TextStyle( color: primaryColor, fontSize: 20, fontWeight: FontWeight.bold, ), overflow: TextOverflow.ellipsis, ), ), ], ), ), // FIXED: Scrollable Content Expanded( child: Scrollbar( thumbVisibility: true, child: SingleChildScrollView( physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Void Type Info _buildInfoCard( icon: Icons.category, title: 'Tipe Void', content: widget.voidType == 'all' ? 'Seluruh Pesanan' : 'Item Tertentu', ), SizedBox(height: 16), // Void Reason _buildInfoCard( icon: Icons.note_alt, title: 'Alasan Void', content: widget.voidReason, ), SizedBox(height: 16), // Voided Items (if item void) if (widget.voidType == 'item' && widget.voidedItems != null) ...[ Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade300), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: EdgeInsets.all(6), decoration: BoxDecoration( color: Colors.grey.shade200, borderRadius: BorderRadius.circular(6), ), child: Icon( Icons.list_alt, color: Colors.grey.shade700, size: 18, ), ), SizedBox(width: 8), Expanded( child: Text( 'Item yang Divoid', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.grey.shade800, ), overflow: TextOverflow.ellipsis, ), ), ], ), SizedBox(height: 12), // Items list (tidak nested scroll) ...widget.voidedItems! .map((item) => _buildVoidedItemCard(item)) .toList(), ], ), ), SizedBox(height: 16), ], // Timestamp _buildInfoCard( icon: Icons.access_time, title: 'Waktu Void', content: (DateTime.now()).toFormattedDate3(), ), SizedBox(height: 32), ], ), ), ), ), Padding( padding: const EdgeInsets.symmetric( vertical: 16, horizontal: 20, ), child: Row( children: [ Expanded( child: Button.outlined( height: 50, onPressed: () { context.pushReplacement(DashboardPage()); }, icon: Icon(Icons.home, size: 20), label: 'Kembali ke Beranda', ), ), SpaceWidth(12), Expanded( child: Button.filled( height: 50, onPressed: _printVoidReceipt, icon: Icon(Icons.print, size: 20), label: 'Cetak Struk', ), ), ], ), ), ], ), ); }, ); } Widget _buildInfoCard({ required IconData icon, required String title, required String content, }) { return Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade300), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.grey.shade200, borderRadius: BorderRadius.circular(8), ), child: Icon( icon, color: Colors.grey.shade700, size: 20, ), ), SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ), SizedBox(height: 4), Text( content, style: TextStyle( fontSize: 14, color: Colors.grey[700], height: 1.4, ), ), ], ), ), ], ), ); } Widget _buildVoidedItemCard(OrderItem item) { return Container( margin: EdgeInsets.only(bottom: 8), padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey.shade300), ), child: Row( children: [ Container( width: 8, height: 8, decoration: BoxDecoration( color: Colors.grey.shade400, shape: BoxShape.circle, ), ), SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.productName ?? 'Unknown Product', style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14, ), overflow: TextOverflow.ellipsis, ), Text( 'Qty: ${item.quantity}', style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), ), Container( padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.grey.shade200, borderRadius: BorderRadius.circular(6), ), child: Text( (item.totalPrice ?? 0).currencyFormatRpV2, style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: Colors.grey.shade700, ), ), ), ], ), ); } Widget _buildBackgroundPattern() { return Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ Colors.grey.shade50, Colors.grey.shade100, ], ), ), child: CustomPaint( painter: PatternPainter(), size: Size.infinite, ), ); } void _printVoidReceipt() {} }