Files
afterwork/lib/domain/entities/establishment.dart
dahoud 92612abbd7 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
2026-01-10 10:43:17 +00:00

217 lines
5.2 KiB
Dart

import 'package:equatable/equatable.dart';
/// Entité de domaine représentant un établissement.
///
/// Un établissement est un lieu physique (bar, restaurant, club, etc.)
/// où peuvent se dérouler des événements Afterwork.
class Establishment extends Equatable {
const Establishment({
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,
});
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; // Note moyenne sur 5
final PriceRange? priceRange;
final int? capacity; // Capacité maximale
final List<String> amenities; // WiFi, Terrasse, Parking, etc.
final String? openingHours;
final double? latitude;
final double? longitude;
/// Adresse complète formatée
String get fullAddress => '$address, $postalCode $city';
/// Indique si l'établissement a une localisation
bool get hasLocation => latitude != null && longitude != null;
@override
List<Object?> get props => [
id,
name,
type,
address,
city,
postalCode,
description,
phoneNumber,
email,
website,
imageUrl,
rating,
priceRange,
capacity,
amenities,
openingHours,
latitude,
longitude,
];
/// Crée une copie de cet établissement avec des valeurs modifiées.
Establishment copyWith({
String? id,
String? name,
EstablishmentType? type,
String? address,
String? city,
String? postalCode,
String? description,
String? phoneNumber,
String? email,
String? website,
String? imageUrl,
double? rating,
PriceRange? priceRange,
int? capacity,
List<String>? amenities,
String? openingHours,
double? latitude,
double? longitude,
}) {
return Establishment(
id: id ?? this.id,
name: name ?? this.name,
type: type ?? this.type,
address: address ?? this.address,
city: city ?? this.city,
postalCode: postalCode ?? this.postalCode,
description: description ?? this.description,
phoneNumber: phoneNumber ?? this.phoneNumber,
email: email ?? this.email,
website: website ?? this.website,
imageUrl: imageUrl ?? this.imageUrl,
rating: rating ?? this.rating,
priceRange: priceRange ?? this.priceRange,
capacity: capacity ?? this.capacity,
amenities: amenities ?? this.amenities,
openingHours: openingHours ?? this.openingHours,
latitude: latitude ?? this.latitude,
longitude: longitude ?? this.longitude,
);
}
}
/// Type d'établissement.
enum EstablishmentType {
bar,
restaurant,
club,
cafe,
lounge,
pub,
brewery,
winery,
other,
}
/// Fourchette de prix.
enum PriceRange {
cheap, // €
moderate, // €€
expensive, // €€€
luxury, // €€€€
}
/// Extensions pour faciliter l'utilisation.
extension EstablishmentTypeExtension on EstablishmentType {
String get displayName {
switch (this) {
case EstablishmentType.bar:
return 'Bar';
case EstablishmentType.restaurant:
return 'Restaurant';
case EstablishmentType.club:
return 'Club';
case EstablishmentType.cafe:
return 'Café';
case EstablishmentType.lounge:
return 'Lounge';
case EstablishmentType.pub:
return 'Pub';
case EstablishmentType.brewery:
return 'Brasserie';
case EstablishmentType.winery:
return 'Cave à vin';
case EstablishmentType.other:
return 'Autre';
}
}
String get icon {
switch (this) {
case EstablishmentType.bar:
return '🍸';
case EstablishmentType.restaurant:
return '🍽️';
case EstablishmentType.club:
return '💃';
case EstablishmentType.cafe:
return '';
case EstablishmentType.lounge:
return '🛋️';
case EstablishmentType.pub:
return '🍺';
case EstablishmentType.brewery:
return '🍻';
case EstablishmentType.winery:
return '🍷';
case EstablishmentType.other:
return '📍';
}
}
}
extension PriceRangeExtension on PriceRange {
String get symbol {
switch (this) {
case PriceRange.cheap:
return '';
case PriceRange.moderate:
return '€€';
case PriceRange.expensive:
return '€€€';
case PriceRange.luxury:
return '€€€€';
}
}
String get displayName {
switch (this) {
case PriceRange.cheap:
return 'Économique';
case PriceRange.moderate:
return 'Modéré';
case PriceRange.expensive:
return 'Cher';
case PriceRange.luxury:
return 'Luxe';
}
}
}