// lib/features/events/models/event_models.dart import '../../../core/api/api_endpoints.dart'; class EventTypeModel { final int id; final String name; final String? iconUrl; EventTypeModel({required this.id, required this.name, this.iconUrl}); /// Resolve a relative media path (e.g. `/media/...`) to a full URL. static String? _resolveMediaUrl(String? raw) { if (raw == null || raw.isEmpty) return null; if (raw.startsWith('http://') || raw.startsWith('https://')) return raw; return '${ApiEndpoints.mediaBaseUrl}$raw'; } factory EventTypeModel.fromJson(Map j) { return EventTypeModel( id: j['id'] as int, name: (j['event_type'] ?? j['name'] ?? '') as String, iconUrl: _resolveMediaUrl((j['event_type_icon'] ?? j['icon_url']) as String?), ); } } class EventImageModel { final bool isPrimary; final String image; EventImageModel({required this.isPrimary, required this.image}); factory EventImageModel.fromJson(Map j) { return EventImageModel( isPrimary: j['is_primary'] == true, image: EventTypeModel._resolveMediaUrl(j['image'] as String?) ?? '', ); } } class EventModel { final int id; final String name; final String? title; final String? description; final String startDate; // YYYY-MM-DD final String endDate; final String? startTime; final String? endTime; final String? pincode; final String? place; final bool isBookable; final int? eventTypeId; final String? thumbImg; final List images; // NEW fields mapped from backend final String? importantInformation; final String? venueName; final String? eventStatus; final String? cancelledReason; // Geo / location fields final double? latitude; final double? longitude; final String? locationName; // Structured important info list [{title, value}, ...] final List> importantInfo; // Review stats (populated when backend includes them) final double? averageRating; final int? reviewCount; // Contributor fields (EVT-001) final String? contributorId; final String? contributorName; final String? contributorTier; EventModel({ required this.id, required this.name, this.title, this.description, required this.startDate, required this.endDate, this.startTime, this.endTime, this.pincode, this.place, this.isBookable = true, this.eventTypeId, this.thumbImg, this.images = const [], this.importantInformation, this.venueName, this.eventStatus, this.cancelledReason, this.latitude, this.longitude, this.locationName, this.importantInfo = const [], this.averageRating, this.reviewCount, this.contributorId, this.contributorName, this.contributorTier, }); /// Safely parse a double from backend (may arrive as String or num) static double? _parseDouble(dynamic raw) { if (raw == null) return null; if (raw is num) return raw.toDouble(); if (raw is String) return double.tryParse(raw); return null; } /// Safely parse important_info from backend (list of {title, value} maps) static List> _parseImportantInfo(dynamic raw) { if (raw is List) { return raw.map>((e) { if (e is Map) { return { 'title': (e['title'] ?? '').toString(), 'value': (e['value'] ?? '').toString(), }; } return {'title': '', 'value': e.toString()}; }).toList(); } return []; } factory EventModel.fromJson(Map j) { final imgs = []; if (j['images'] is List) { for (final im in j['images']) { if (im is Map) imgs.add(EventImageModel.fromJson(im)); } } return EventModel( id: j['id'] is int ? j['id'] as int : int.parse(j['id'].toString()), name: (j['name'] ?? '') as String, title: j['title'] as String?, description: j['description'] as String?, startDate: (j['start_date'] ?? '') as String, endDate: (j['end_date'] ?? '') as String, startTime: j['start_time'] as String?, endTime: j['end_time'] as String?, pincode: j['pincode'] as String?, place: (j['place'] ?? j['venue_name']) as String?, isBookable: j['is_bookable'] == null ? true : (j['is_bookable'] == true || j['is_bookable'].toString().toLowerCase() == 'true'), eventTypeId: j['event_type'] is int ? j['event_type'] as int : (j['event_type'] != null ? int.tryParse(j['event_type'].toString()) : null), thumbImg: EventTypeModel._resolveMediaUrl(j['thumb_img'] as String?), images: imgs, importantInformation: j['important_information'] as String?, venueName: j['venue_name'] as String?, eventStatus: j['event_status'] as String?, cancelledReason: j['cancelled_reason'] as String?, latitude: _parseDouble(j['latitude']), longitude: _parseDouble(j['longitude']), locationName: j['location_name'] as String?, importantInfo: _parseImportantInfo(j['important_info']), averageRating: (j['average_rating'] as num?)?.toDouble(), reviewCount: (j['review_count'] as num?)?.toInt(), contributorId: j['contributor_id']?.toString(), contributorName: j['contributor_name'] as String?, contributorTier: j['contributor_tier'] as String?, ); } }