130 lines
4.1 KiB
Dart
130 lines
4.1 KiB
Dart
import '../models/coupon_model.dart';
|
|
import './supabase_service.dart';
|
|
|
|
class CouponService {
|
|
/// Fetches coupons with auto-reconnection and exact query logic from requirements
|
|
static Future<List<CouponModel>> getCoupons({
|
|
String? selectedCategory,
|
|
String? sort,
|
|
}) async {
|
|
return await SupabaseService.withAutoReconnect(() async {
|
|
final client = SupabaseService.client;
|
|
|
|
// Exact query from requirements specification
|
|
var query = client
|
|
.from('coupons')
|
|
.select(
|
|
'id, business_name, title, description, valid_until, image_url, category, is_active, created_at',
|
|
);
|
|
|
|
// Apply the exact WHERE conditions from requirements
|
|
query = query.eq('is_active', true);
|
|
|
|
// Handle date filter: (valid_until IS NULL OR valid_until >= CURRENT_DATE)
|
|
final currentDate = DateTime.now().toIso8601String().split('T')[0];
|
|
query = query.or('valid_until.is.null,valid_until.gte.$currentDate');
|
|
|
|
// Category filter: ignore when 'Todos' is selected
|
|
if (selectedCategory != null && selectedCategory != 'Todos') {
|
|
final categoryValue = _mapDisplayCategoryToDbValue(selectedCategory);
|
|
query = query.eq('category', categoryValue);
|
|
}
|
|
|
|
// Apply sorting based on requirements
|
|
final dynamic response;
|
|
if (sort == 'Por vencer') {
|
|
// Sort by expiring first (null values last)
|
|
response = await query.order('valid_until', ascending: true, nullsFirst: false);
|
|
} else {
|
|
// Default: "Más recientes" - sort by created_at descending
|
|
response = await query.order('created_at', ascending: false);
|
|
}
|
|
|
|
return (response as List)
|
|
.map((data) => CouponModel.fromMap(data))
|
|
.toList();
|
|
});
|
|
}
|
|
|
|
/// Maps display category names to database enum values
|
|
static String _mapDisplayCategoryToDbValue(String displayCategory) {
|
|
switch (displayCategory.toLowerCase()) {
|
|
case 'restaurantes':
|
|
return 'restaurantes';
|
|
case 'tiendas':
|
|
return 'tiendas';
|
|
case 'servicios':
|
|
return 'servicios';
|
|
case 'entretenimiento':
|
|
return 'entretenimiento';
|
|
case 'salud':
|
|
return 'salud';
|
|
case 'belleza':
|
|
return 'belleza';
|
|
default:
|
|
return 'restaurantes'; // fallback
|
|
}
|
|
}
|
|
|
|
/// Gets available category options for filtering (Spanish UI)
|
|
static List<String> getCategoryOptions() {
|
|
return [
|
|
'Todos',
|
|
'Restaurantes',
|
|
'Tiendas',
|
|
'Servicios',
|
|
'Entretenimiento',
|
|
'Salud',
|
|
'Belleza',
|
|
];
|
|
}
|
|
|
|
/// Gets available sort options (Spanish UI)
|
|
static List<String> getSortOptions() {
|
|
return ['Más recientes', 'Por vencer'];
|
|
}
|
|
|
|
/// Gets a single coupon by ID with auto-reconnection
|
|
static Future<CouponModel?> getCouponById(String id) async {
|
|
try {
|
|
return await SupabaseService.withAutoReconnect(() async {
|
|
final client = SupabaseService.client;
|
|
final response =
|
|
await client
|
|
.from('coupons')
|
|
.select(
|
|
'id, business_name, title, description, valid_until, image_url, category, is_active, created_at',
|
|
)
|
|
.eq('id', id)
|
|
.eq('is_active', true)
|
|
.single();
|
|
|
|
return CouponModel.fromMap(response);
|
|
});
|
|
} catch (e) {
|
|
// Silent failure - return null
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Counts total coupons for a category with auto-reconnection
|
|
static Future<int> getCouponCount({String? category}) async {
|
|
try {
|
|
return await SupabaseService.withAutoReconnect(() async {
|
|
final client = SupabaseService.client;
|
|
var query = client.from('coupons').select('id').eq('is_active', true);
|
|
|
|
if (category != null && category.toLowerCase() != 'todos') {
|
|
final categoryValue = _mapDisplayCategoryToDbValue(category);
|
|
query = query.eq('category', categoryValue);
|
|
}
|
|
|
|
final response = await query.count();
|
|
return response.count ?? 0;
|
|
});
|
|
} catch (e) {
|
|
// Silent failure - return 0
|
|
return 0;
|
|
}
|
|
}
|
|
} |