fix(chat): Correction race condition + Implémentation TODOs
## Corrections Critiques ### Race Condition - Statuts de Messages - Fix : Les icônes de statut (✓, ✓✓, ✓✓ bleu) ne s'affichaient pas - Cause : WebSocket delivery confirmations arrivaient avant messages locaux - Solution : Pattern Optimistic UI dans chat_bloc.dart - Création message temporaire immédiate - Ajout à la liste AVANT requête HTTP - Remplacement par message serveur à la réponse - Fichier : lib/presentation/state_management/chat_bloc.dart ## Implémentation TODOs (13/21) ### Social (social_header_widget.dart) - ✅ Copier lien du post dans presse-papiers - ✅ Partage natif via Share.share() - ✅ Dialogue de signalement avec 5 raisons ### Partage (share_post_dialog.dart) - ✅ Interface sélection d'amis avec checkboxes - ✅ Partage externe via Share API ### Média (media_upload_service.dart) - ✅ Parsing JSON réponse backend - ✅ Méthode deleteMedia() pour suppression - ✅ Génération miniature vidéo ### Posts (create_post_dialog.dart, edit_post_dialog.dart) - ✅ Extraction URL depuis uploads - ✅ Documentation chargement médias ### Chat (conversations_screen.dart) - ✅ Navigation vers notifications - ✅ ConversationSearchDelegate pour recherche ## Nouveaux Fichiers ### Configuration - build-prod.ps1 : Script build production avec dart-define - lib/core/constants/env_config.dart : Gestion environnements ### Documentation - TODOS_IMPLEMENTED.md : Documentation complète TODOs ## Améliorations ### Architecture - Refactoring injection de dépendances - Amélioration routing et navigation - Optimisation providers (UserProvider, FriendsProvider) ### UI/UX - Amélioration thème et couleurs - Optimisation animations - Meilleure gestion erreurs ### Services - Configuration API avec env_config - Amélioration datasources (events, users) - Optimisation modèles de données
This commit is contained in:
190
lib/data/models/establishment_model.dart
Normal file
190
lib/data/models/establishment_model.dart
Normal file
@@ -0,0 +1,190 @@
|
||||
import '../../domain/entities/establishment.dart';
|
||||
|
||||
/// Modèle de données pour les établissements (Data Transfer Object).
|
||||
class EstablishmentModel {
|
||||
EstablishmentModel({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.type,
|
||||
required this.address,
|
||||
required this.city,
|
||||
required this.postalCode,
|
||||
this.description,
|
||||
this.phoneNumber,
|
||||
this.email,
|
||||
this.website,
|
||||
this.imageUrl,
|
||||
this.rating,
|
||||
this.priceRange,
|
||||
this.capacity,
|
||||
this.amenities = const [],
|
||||
this.openingHours,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
});
|
||||
|
||||
/// Factory pour créer un [EstablishmentModel] à partir d'un JSON.
|
||||
factory EstablishmentModel.fromJson(Map<String, dynamic> json) {
|
||||
return EstablishmentModel(
|
||||
id: _parseId(json, 'id', ''),
|
||||
name: _parseString(json, 'name', ''),
|
||||
type: _parseType(json['type'] as String?),
|
||||
address: _parseString(json, 'address', ''),
|
||||
city: _parseString(json, 'city', ''),
|
||||
postalCode: _parseString(json, 'postalCode', ''),
|
||||
description: json['description'] as String?,
|
||||
phoneNumber: json['phoneNumber'] as String?,
|
||||
email: json['email'] as String?,
|
||||
website: json['website'] as String?,
|
||||
imageUrl: json['imageUrl'] as String?,
|
||||
rating: json['rating'] != null ? (json['rating'] as num).toDouble() : null,
|
||||
priceRange: _parsePriceRange(json['priceRange'] as String?),
|
||||
capacity: json['capacity'] as int?,
|
||||
amenities: json['amenities'] != null
|
||||
? List<String>.from(json['amenities'] as List)
|
||||
: [],
|
||||
openingHours: json['openingHours'] as String?,
|
||||
latitude: json['latitude'] != null ? (json['latitude'] as num).toDouble() : null,
|
||||
longitude: json['longitude'] != null ? (json['longitude'] as num).toDouble() : null,
|
||||
);
|
||||
}
|
||||
|
||||
final String id;
|
||||
final String name;
|
||||
final EstablishmentType type;
|
||||
final String address;
|
||||
final String city;
|
||||
final String postalCode;
|
||||
final String? description;
|
||||
final String? phoneNumber;
|
||||
final String? email;
|
||||
final String? website;
|
||||
final String? imageUrl;
|
||||
final double? rating;
|
||||
final PriceRange? priceRange;
|
||||
final int? capacity;
|
||||
final List<String> amenities;
|
||||
final String? openingHours;
|
||||
final double? latitude;
|
||||
final double? longitude;
|
||||
|
||||
/// Convertit ce modèle en JSON pour l'envoi vers l'API.
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'type': _typeToString(type),
|
||||
'address': address,
|
||||
'city': city,
|
||||
'postalCode': postalCode,
|
||||
if (description != null) 'description': description,
|
||||
if (phoneNumber != null) 'phoneNumber': phoneNumber,
|
||||
if (email != null) 'email': email,
|
||||
if (website != null) 'website': website,
|
||||
if (imageUrl != null) 'imageUrl': imageUrl,
|
||||
if (rating != null) 'rating': rating,
|
||||
if (priceRange != null) 'priceRange': _priceRangeToString(priceRange!),
|
||||
if (capacity != null) 'capacity': capacity,
|
||||
if (amenities.isNotEmpty) 'amenities': amenities,
|
||||
if (openingHours != null) 'openingHours': openingHours,
|
||||
if (latitude != null) 'latitude': latitude,
|
||||
if (longitude != null) 'longitude': longitude,
|
||||
};
|
||||
}
|
||||
|
||||
/// Convertit ce modèle vers une entité de domaine [Establishment].
|
||||
Establishment toEntity() {
|
||||
return Establishment(
|
||||
id: id,
|
||||
name: name,
|
||||
type: type,
|
||||
address: address,
|
||||
city: city,
|
||||
postalCode: postalCode,
|
||||
description: description,
|
||||
phoneNumber: phoneNumber,
|
||||
email: email,
|
||||
website: website,
|
||||
imageUrl: imageUrl,
|
||||
rating: rating,
|
||||
priceRange: priceRange,
|
||||
capacity: capacity,
|
||||
amenities: amenities,
|
||||
openingHours: openingHours,
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
);
|
||||
}
|
||||
|
||||
// Méthodes de parsing
|
||||
static String _parseString(Map<String, dynamic> json, String key, String defaultValue) {
|
||||
return json[key] as String? ?? defaultValue;
|
||||
}
|
||||
|
||||
static String _parseId(Map<String, dynamic> json, String key, String defaultValue) {
|
||||
final value = json[key];
|
||||
if (value == null) return defaultValue;
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
static EstablishmentType _parseType(String? type) {
|
||||
if (type == null) return EstablishmentType.other;
|
||||
|
||||
switch (type.toLowerCase()) {
|
||||
case 'bar':
|
||||
return EstablishmentType.bar;
|
||||
case 'restaurant':
|
||||
return EstablishmentType.restaurant;
|
||||
case 'club':
|
||||
return EstablishmentType.club;
|
||||
case 'cafe':
|
||||
case 'café':
|
||||
return EstablishmentType.cafe;
|
||||
case 'lounge':
|
||||
return EstablishmentType.lounge;
|
||||
case 'pub':
|
||||
return EstablishmentType.pub;
|
||||
case 'brewery':
|
||||
case 'brasserie':
|
||||
return EstablishmentType.brewery;
|
||||
case 'winery':
|
||||
case 'cave':
|
||||
return EstablishmentType.winery;
|
||||
default:
|
||||
return EstablishmentType.other;
|
||||
}
|
||||
}
|
||||
|
||||
static PriceRange? _parsePriceRange(String? priceRange) {
|
||||
if (priceRange == null) return null;
|
||||
|
||||
switch (priceRange.toLowerCase()) {
|
||||
case 'cheap':
|
||||
case 'économique':
|
||||
case '€':
|
||||
return PriceRange.cheap;
|
||||
case 'moderate':
|
||||
case 'modéré':
|
||||
case '€€':
|
||||
return PriceRange.moderate;
|
||||
case 'expensive':
|
||||
case 'cher':
|
||||
case '€€€':
|
||||
return PriceRange.expensive;
|
||||
case 'luxury':
|
||||
case 'luxe':
|
||||
case '€€€€':
|
||||
return PriceRange.luxury;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static String _typeToString(EstablishmentType type) {
|
||||
return type.toString().split('.').last;
|
||||
}
|
||||
|
||||
static String _priceRangeToString(PriceRange priceRange) {
|
||||
return priceRange.toString().split('.').last;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user