Files
SIB/old/lib/presentation/coupons_screen/coupons_screen.dart

257 lines
6.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:sizer/sizer.dart';
import '../../core/app_export.dart';
import '../../models/coupon_model.dart';
import '../../services/coupon_service.dart';
import '../../theme/app_theme.dart';
import '../../widgets/custom_bottom_bar.dart';
import './widgets/category_filter_chips.dart';
import './widgets/coupon_card_widget.dart';
import './widgets/coupon_detail_modal.dart';
import './widgets/empty_state_widget.dart';
import './widgets/sort_dropdown.dart';
class CouponsScreen extends StatefulWidget {
const CouponsScreen({super.key});
@override
State<CouponsScreen> createState() => _CouponsScreenState();
}
class _CouponsScreenState extends State<CouponsScreen> {
final ScrollController _scrollController = ScrollController();
bool _isLoading = true;
bool _isRefreshing = false;
String _selectedCategory = 'Todos';
String _selectedSort = 'Más recientes';
List<CouponModel> _coupons = [];
@override
void initState() {
super.initState();
_loadCoupons();
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
/// Load coupons with silent error handling - no user error messages
Future<void> _loadCoupons() async {
try {
setState(() {
_isLoading = true;
});
final coupons = await CouponService.getCoupons(
selectedCategory: _selectedCategory,
sort: _selectedSort,
);
setState(() {
_coupons = coupons;
_isLoading = false;
});
} catch (e) {
// Silent failure - show empty state but don't show error to user
setState(() {
_coupons = [];
_isLoading = false;
});
}
}
/// Refresh coupons with silent error handling
Future<void> _refreshCoupons() async {
setState(() {
_isRefreshing = true;
});
HapticFeedback.lightImpact();
try {
final coupons = await CouponService.getCoupons(
selectedCategory: _selectedCategory,
sort: _selectedSort,
);
setState(() {
_coupons = coupons;
});
} catch (e) {
// Silent failure - keep existing coupons, don't show error
} finally {
setState(() {
_isRefreshing = false;
});
}
}
/// Handle category change and auto-refresh data
void _onCategoryChanged(String category) {
if (_selectedCategory != category) {
setState(() {
_selectedCategory = category;
});
_loadCoupons(); // Automatically refresh when filters change
}
}
/// Handle sort change and auto-refresh data
void _onSortChanged(String sort) {
if (_selectedSort != sort) {
setState(() {
_selectedSort = sort;
});
_loadCoupons(); // Automatically refresh when sorting changes
}
}
void _showCouponDetail(CouponModel coupon) {
HapticFeedback.lightImpact();
showDialog(
context: context,
builder: (context) => CouponDetailModal(coupon: coupon),
);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
backgroundColor: theme.scaffoldBackgroundColor,
appBar: AppBar(
title: Text(
'Cupones',
style: theme.textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w600,
),
),
backgroundColor: theme.colorScheme.surface,
elevation: 0,
),
body: Column(
children: [
// Category Filter Chips (Spanish UI)
CategoryFilterChips(
selectedCategory: _selectedCategory,
onCategorySelected: _onCategoryChanged,
),
// Sort Dropdown (Spanish UI)
Container(
padding: EdgeInsets.symmetric(vertical: 1.h),
color: theme.colorScheme.surface,
child: SortDropdown(
selectedSort: _selectedSort,
onSortChanged: _onSortChanged,
),
),
// Content
Expanded(child: _buildContent()),
],
),
bottomNavigationBar: CustomBottomBar(
currentIndex: 2,
onTap: (index) {
switch (index) {
case 0:
Navigator.pushReplacementNamed(context, '/map-screen');
break;
case 1:
Navigator.pushReplacementNamed(context, '/schedules-screen');
break;
case 2:
// Already on coupons screen
break;
}
},
),
);
}
Widget _buildContent() {
final theme = Theme.of(context);
if (_isLoading) {
return Center(
child: CircularProgressIndicator(color: AppTheme.accentYellow),
);
}
// No error states shown to user - only empty states
if (_coupons.isEmpty) {
final isFiltered = _selectedCategory != 'Todos';
return EmptyStateWidget(
title:
isFiltered
? 'No hay cupones disponibles para esta categoría.'
: 'Aún no hay cupones registrados.',
subtitle:
isFiltered
? 'Intenta seleccionando otra categoría'
: 'Vuelve pronto para ver nuevas ofertas',
actionText: isFiltered ? 'Ver todos' : null,
onActionPressed: isFiltered ? () => _onCategoryChanged('Todos') : null,
);
}
return RefreshIndicator(
onRefresh: _refreshCoupons,
color: AppTheme.accentYellow,
backgroundColor: theme.colorScheme.surface,
child: GridView.builder(
controller: _scrollController,
padding: EdgeInsets.all(4.w),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: _getGridCrossAxisCount(),
crossAxisSpacing: 4.w,
mainAxisSpacing: 4.w,
childAspectRatio: 0.75,
),
itemCount: _coupons.length + (_isRefreshing ? 2 : 0),
itemBuilder: (context, index) {
if (index >= _coupons.length) {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: theme.colorScheme.surface,
),
child: Center(
child: CircularProgressIndicator(
color: AppTheme.accentYellow,
strokeWidth: 2,
),
),
),
);
}
final coupon = _coupons[index];
return CouponCardWidget(
coupon: coupon,
onTap: () => _showCouponDetail(coupon),
);
},
),
);
}
int _getGridCrossAxisCount() {
if (MediaQuery.of(context).size.width > 768) {
return 3; // Tablet
}
return 2; // Phone
}
}