Initial commit: SIBU 2.0 MISSION

This commit is contained in:
2026-02-21 09:53:31 -05:00
commit 0c7aa53c8b
400 changed files with 67708 additions and 0 deletions

View File

@ -0,0 +1,130 @@
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;
}
}
}