import 'package:flutter/material.dart'; import '../../../common/theme/theme.dart'; class ErrorWidget extends StatefulWidget { final String? title; final String? message; final VoidCallback? onRetry; final String? errorCode; final IconData? errorIcon; final double? width; final double? height; final bool showRetryButton; final EdgeInsets? padding; const ErrorWidget({ super.key, this.title, this.message, this.onRetry, this.errorCode, this.errorIcon, this.width, this.height, this.showRetryButton = true, this.padding, }); @override State createState() => _ErrorWidgetState(); } class _ErrorWidgetState extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _fadeAnimation; late Animation _scaleAnimation; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 600), vsync: this, ); _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); _scaleAnimation = Tween(begin: 0.8, end: 1.0).animate( CurvedAnimation(parent: _animationController, curve: Curves.elasticOut), ); _animationController.forward(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container( width: widget.width, height: widget.height, padding: widget.padding ?? const EdgeInsets.all(24), child: FadeTransition( opacity: _fadeAnimation, child: ScaleTransition( scale: _scaleAnimation, child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ // Error Icon Container( width: 80, height: 80, decoration: BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: [ AppColor.error.withOpacity(0.1), AppColor.warning.withOpacity(0.1), ], ), border: Border.all( color: AppColor.error.withOpacity(0.2), width: 2, ), ), child: Icon( widget.errorIcon ?? Icons.error_outline_rounded, size: 40, color: AppColor.error, ), ), const SizedBox(height: 16), // Title if (widget.title != null) Text( widget.title!, style: AppStyle.xl.copyWith( fontWeight: FontWeight.bold, color: AppColor.textPrimary, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), // Message Text( widget.message ?? 'Terjadi kesalahan tidak terduga', style: AppStyle.md.copyWith( color: AppColor.textSecondary, height: 1.4, ), textAlign: TextAlign.center, ), // Error Code if (widget.errorCode != null) ...[ const SizedBox(height: 12), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: AppColor.error.withOpacity(0.1), borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColor.error.withOpacity(0.2)), ), child: Text( 'Error: ${widget.errorCode}', style: AppStyle.xs.copyWith( color: AppColor.error, fontWeight: FontWeight.w500, ), ), ), ], // Retry Button if (widget.showRetryButton && widget.onRetry != null) ...[ const SizedBox(height: 20), ElevatedButton.icon( onPressed: widget.onRetry, icon: const Icon(Icons.refresh_rounded, size: 18), label: const Text('Coba Lagi'), style: ElevatedButton.styleFrom( backgroundColor: AppColor.primary, foregroundColor: AppColor.textWhite, padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 12, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ), ], ], ), ), ), ); } }