feat:implementacion grafica

This commit is contained in:
25030248hasel
2026-05-22 18:06:11 -06:00
parent 83be5a1a40
commit ffb5bdb346
16 changed files with 1819 additions and 98 deletions

View File

@@ -0,0 +1,27 @@
import 'package:equatable/equatable.dart';
/// Entidad de dominio que representa un usuario autenticado.
/// Almacena únicamente el token (simulado JWT) y el rol,
/// sin datos de ubicación o rastreo.
class AuthUser extends Equatable {
final String token;
final String email;
final String role; // 'citizen' | 'operator'
final DateTime issuedAt;
final DateTime expiresAt;
const AuthUser({
required this.token,
required this.email,
required this.role,
required this.issuedAt,
required this.expiresAt,
});
bool get isExpired => DateTime.now().isAfter(expiresAt);
bool get isValid => token.isNotEmpty && !isExpired;
@override
List<Object?> get props => [token, email, role, issuedAt, expiresAt];
}

View File

@@ -0,0 +1,18 @@
import '../entities/auth_user.dart';
/// Contrato abstracto del repositorio de autenticación.
/// El dominio no conoce la implementación concreta (Clean Architecture).
abstract class AuthRepository {
/// Autentica al usuario con email/teléfono y contraseña.
/// Retorna un [AuthUser] con token JWT simulado en esta fase.
Future<AuthUser> login({
required String identifier,
required String password,
});
/// Cierra la sesión del usuario actual.
Future<void> logout();
/// Verifica si existe una sesión activa guardada localmente.
Future<AuthUser?> getStoredSession();
}

View File

@@ -0,0 +1,2 @@
[LocalizedFileNames]
auth_repository.dart=@auth_repository,0

View File

@@ -0,0 +1,44 @@
import '../entities/auth_user.dart';
import '../repositories/auth_repository.dart';
/// Caso de uso: Iniciar sesión.
/// Encapsula la lógica de negocio para autenticar un usuario.
class LoginUseCase {
final AuthRepository _repository;
const LoginUseCase(this._repository);
Future<AuthUser> execute({
required String identifier,
required String password,
}) async {
if (identifier.trim().isEmpty) {
throw ArgumentError('El correo o teléfono no puede estar vacío.');
}
if (password.length < 6) {
throw ArgumentError('La contraseña debe tener al menos 6 caracteres.');
}
return _repository.login(
identifier: identifier.trim(),
password: password,
);
}
}
/// Caso de uso: Cerrar sesión.
class LogoutUseCase {
final AuthRepository _repository;
const LogoutUseCase(this._repository);
Future<void> execute() => _repository.logout();
}
/// Caso de uso: Recuperar sesión almacenada.
class GetStoredSessionUseCase {
final AuthRepository _repository;
const GetStoredSessionUseCase(this._repository);
Future<AuthUser?> execute() => _repository.getStoredSession();
}

View File

@@ -0,0 +1,2 @@
[LocalizedFileNames]
auth_usecases.dart=@auth_usecases,0