first commit

This commit is contained in:
DahoudG
2025-08-20 21:00:35 +00:00
commit b2a23bdf89
583 changed files with 243074 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
import 'package:equatable/equatable.dart';
import 'user_info.dart';
/// États d'authentification possibles
enum AuthStatus {
unknown, // État initial
checking, // Vérification en cours
authenticated,// Utilisateur connecté
unauthenticated, // Utilisateur non connecté
expired, // Session expirée
error, // Erreur d'authentification
}
/// État d'authentification de l'application
class AuthState extends Equatable {
final AuthStatus status;
final UserInfo? user;
final String? accessToken;
final String? refreshToken;
final DateTime? expiresAt;
final String? errorMessage;
final bool isLoading;
const AuthState({
this.status = AuthStatus.unknown,
this.user,
this.accessToken,
this.refreshToken,
this.expiresAt,
this.errorMessage,
this.isLoading = false,
});
/// État initial inconnu
const AuthState.unknown() : this(status: AuthStatus.unknown);
/// État de vérification
const AuthState.checking() : this(
status: AuthStatus.checking,
isLoading: true,
);
/// État authentifié
const AuthState.authenticated({
required UserInfo user,
required String accessToken,
required String refreshToken,
required DateTime expiresAt,
}) : this(
status: AuthStatus.authenticated,
user: user,
accessToken: accessToken,
refreshToken: refreshToken,
expiresAt: expiresAt,
isLoading: false,
);
/// État non authentifié
const AuthState.unauthenticated({String? errorMessage}) : this(
status: AuthStatus.unauthenticated,
errorMessage: errorMessage,
isLoading: false,
);
/// État de session expirée
const AuthState.expired() : this(
status: AuthStatus.expired,
isLoading: false,
);
/// État d'erreur
const AuthState.error(String errorMessage) : this(
status: AuthStatus.error,
errorMessage: errorMessage,
isLoading: false,
);
/// Vérifie si l'utilisateur est connecté
bool get isAuthenticated => status == AuthStatus.authenticated;
/// Vérifie si la session est valide
bool get isSessionValid {
if (!isAuthenticated || expiresAt == null) return false;
return DateTime.now().isBefore(expiresAt!);
}
/// Vérifie si la session expire bientôt
bool get isExpiringSoon {
if (!isAuthenticated || expiresAt == null) return false;
final threshold = DateTime.now().add(const Duration(minutes: 5));
return expiresAt!.isBefore(threshold);
}
/// Crée une copie avec des modifications
AuthState copyWith({
AuthStatus? status,
UserInfo? user,
String? accessToken,
String? refreshToken,
DateTime? expiresAt,
String? errorMessage,
bool? isLoading,
}) {
return AuthState(
status: status ?? this.status,
user: user ?? this.user,
accessToken: accessToken ?? this.accessToken,
refreshToken: refreshToken ?? this.refreshToken,
expiresAt: expiresAt ?? this.expiresAt,
errorMessage: errorMessage ?? this.errorMessage,
isLoading: isLoading ?? this.isLoading,
);
}
/// Crée une copie en effaçant les données sensibles
AuthState clearSensitiveData() {
return AuthState(
status: status,
user: user,
errorMessage: errorMessage,
isLoading: isLoading,
);
}
@override
List<Object?> get props => [
status,
user,
accessToken,
refreshToken,
expiresAt,
errorMessage,
isLoading,
];
@override
String toString() {
return 'AuthState(status: $status, user: ${user?.email}, isLoading: $isLoading, error: $errorMessage)';
}
}

View File

@@ -0,0 +1,50 @@
import 'package:equatable/equatable.dart';
/// Modèle de requête de connexion
class LoginRequest extends Equatable {
final String email;
final String password;
final bool rememberMe;
const LoginRequest({
required this.email,
required this.password,
this.rememberMe = false,
});
Map<String, dynamic> toJson() {
return {
'email': email,
'password': password,
'rememberMe': rememberMe,
};
}
factory LoginRequest.fromJson(Map<String, dynamic> json) {
return LoginRequest(
email: json['email'] ?? '',
password: json['password'] ?? '',
rememberMe: json['rememberMe'] ?? false,
);
}
LoginRequest copyWith({
String? email,
String? password,
bool? rememberMe,
}) {
return LoginRequest(
email: email ?? this.email,
password: password ?? this.password,
rememberMe: rememberMe ?? this.rememberMe,
);
}
@override
List<Object?> get props => [email, password, rememberMe];
@override
String toString() {
return 'LoginRequest(email: $email, rememberMe: $rememberMe)';
}
}

View File

@@ -0,0 +1,96 @@
import 'package:equatable/equatable.dart';
import 'user_info.dart';
/// Modèle de réponse de connexion
class LoginResponse extends Equatable {
final String accessToken;
final String refreshToken;
final String tokenType;
final DateTime expiresAt;
final DateTime refreshExpiresAt;
final UserInfo user;
const LoginResponse({
required this.accessToken,
required this.refreshToken,
required this.tokenType,
required this.expiresAt,
required this.refreshExpiresAt,
required this.user,
});
/// Vérifie si le token d'accès est expiré
bool get isAccessTokenExpired {
return DateTime.now().isAfter(expiresAt);
}
/// Vérifie si le refresh token est expiré
bool get isRefreshTokenExpired {
return DateTime.now().isAfter(refreshExpiresAt);
}
/// Vérifie si le token expire dans les prochaines minutes
bool isExpiringSoon({int minutes = 5}) {
final threshold = DateTime.now().add(Duration(minutes: minutes));
return expiresAt.isBefore(threshold);
}
factory LoginResponse.fromJson(Map<String, dynamic> json) {
return LoginResponse(
accessToken: json['accessToken'] ?? '',
refreshToken: json['refreshToken'] ?? '',
tokenType: json['tokenType'] ?? 'Bearer',
expiresAt: json['expiresAt'] != null
? DateTime.parse(json['expiresAt'])
: DateTime.now().add(const Duration(minutes: 15)),
refreshExpiresAt: json['refreshExpiresAt'] != null
? DateTime.parse(json['refreshExpiresAt'])
: DateTime.now().add(const Duration(days: 7)),
user: UserInfo.fromJson(json['user'] ?? {}),
);
}
Map<String, dynamic> toJson() {
return {
'accessToken': accessToken,
'refreshToken': refreshToken,
'tokenType': tokenType,
'expiresAt': expiresAt.toIso8601String(),
'refreshExpiresAt': refreshExpiresAt.toIso8601String(),
'user': user.toJson(),
};
}
LoginResponse copyWith({
String? accessToken,
String? refreshToken,
String? tokenType,
DateTime? expiresAt,
DateTime? refreshExpiresAt,
UserInfo? user,
}) {
return LoginResponse(
accessToken: accessToken ?? this.accessToken,
refreshToken: refreshToken ?? this.refreshToken,
tokenType: tokenType ?? this.tokenType,
expiresAt: expiresAt ?? this.expiresAt,
refreshExpiresAt: refreshExpiresAt ?? this.refreshExpiresAt,
user: user ?? this.user,
);
}
@override
List<Object?> get props => [
accessToken,
refreshToken,
tokenType,
expiresAt,
refreshExpiresAt,
user,
];
@override
String toString() {
return 'LoginResponse(tokenType: $tokenType, user: ${user.email}, expiresAt: $expiresAt)';
}
}

View File

@@ -0,0 +1,5 @@
// Export all auth models
export 'auth_state.dart';
export 'login_request.dart';
export 'login_response.dart';
export 'user_info.dart';

View File

@@ -0,0 +1,90 @@
import 'package:equatable/equatable.dart';
/// Modèle des informations utilisateur
class UserInfo extends Equatable {
final String id;
final String email;
final String firstName;
final String lastName;
final String role;
final String? profilePicture;
final bool isActive;
const UserInfo({
required this.id,
required this.email,
required this.firstName,
required this.lastName,
required this.role,
this.profilePicture,
required this.isActive,
});
String get fullName => '$firstName $lastName';
String get initials {
final f = firstName.isNotEmpty ? firstName[0] : '';
final l = lastName.isNotEmpty ? lastName[0] : '';
return '$f$l'.toUpperCase();
}
factory UserInfo.fromJson(Map<String, dynamic> json) {
return UserInfo(
id: json['id'] ?? '',
email: json['email'] ?? '',
firstName: json['firstName'] ?? '',
lastName: json['lastName'] ?? '',
role: json['role'] ?? 'membre',
profilePicture: json['profilePicture'],
isActive: json['isActive'] ?? true,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'email': email,
'firstName': firstName,
'lastName': lastName,
'role': role,
'profilePicture': profilePicture,
'isActive': isActive,
};
}
UserInfo copyWith({
String? id,
String? email,
String? firstName,
String? lastName,
String? role,
String? profilePicture,
bool? isActive,
}) {
return UserInfo(
id: id ?? this.id,
email: email ?? this.email,
firstName: firstName ?? this.firstName,
lastName: lastName ?? this.lastName,
role: role ?? this.role,
profilePicture: profilePicture ?? this.profilePicture,
isActive: isActive ?? this.isActive,
);
}
@override
List<Object?> get props => [
id,
email,
firstName,
lastName,
role,
profilePicture,
isActive,
];
@override
String toString() {
return 'UserInfo(id: $id, email: $email, fullName: $fullName, role: $role, isActive: $isActive)';
}
}