diff --git a/lib/assets/images/background.webp b/lib/assets/images/background.webp new file mode 100644 index 0000000..7bd2a94 Binary files /dev/null and b/lib/assets/images/background.webp differ diff --git a/lib/core/constants/urls.dart b/lib/core/constants/urls.dart index 601083b..1f807fd 100644 --- a/lib/core/constants/urls.dart +++ b/lib/core/constants/urls.dart @@ -1,5 +1,5 @@ class Urls { - static const String baseUrl = 'http://localhost:8085'; + static const String baseUrl = 'http://192.168.1.145:8085'; // static const String login = baseUrl + 'auth/login'; // static const String events = baseUrl + 'events'; // Ajoute d'autres URLs ici diff --git a/lib/core/errors/exceptions.dart b/lib/core/errors/exceptions.dart index 451f647..3d1ab7a 100644 --- a/lib/core/errors/exceptions.dart +++ b/lib/core/errors/exceptions.dart @@ -1,3 +1,12 @@ class ServerException implements Exception {} class CacheException implements Exception {} + +class AuthenticationException implements Exception { + final String message; + + AuthenticationException(this.message); + + @override + String toString() => 'AuthenticationException: $message'; +} diff --git a/lib/data/datasources/user_remote_data_source.dart b/lib/data/datasources/user_remote_data_source.dart index 62f3464..447b5df 100644 --- a/lib/data/datasources/user_remote_data_source.dart +++ b/lib/data/datasources/user_remote_data_source.dart @@ -10,6 +10,30 @@ class UserRemoteDataSource { UserRemoteDataSource(this.client); + Future authenticateUser(String email, String password) async { + if (email.isEmpty || password.isEmpty) { + throw Exception('Email ou mot de passe vide'); + } + + final response = await client.post( + Uri.parse('${Urls.baseUrl}/users/authenticate'), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({ + 'email': email, + 'motDePasse': password, + }), + ); + + if (response.statusCode == 200) { + final jsonResponse = json.decode(response.body); + return UserModel.fromJson(jsonResponse); + } else if (response.statusCode == 401) { + throw AuthenticationException('Email ou mot de passe incorrect'); + } else { + throw ServerException(); + } + } + Future getUser(String id) async { final response = await client.get(Uri.parse('${Urls.baseUrl}/user/$id')); diff --git a/lib/data/datasources/user_repository_impl.dart b/lib/data/datasources/user_repository_impl.dart index 164698b..020e840 100644 --- a/lib/data/datasources/user_repository_impl.dart +++ b/lib/data/datasources/user_repository_impl.dart @@ -1,6 +1,7 @@ import 'package:afterwork/domain/entities/user.dart'; import 'package:afterwork/domain/repositories/user_repository.dart'; import 'package:afterwork/data/datasources/user_remote_data_source.dart'; +import 'package:afterwork/data/models/user_model.dart'; class UserRepositoryImpl implements UserRepository { final UserRemoteDataSource remoteDataSource; @@ -9,6 +10,12 @@ class UserRepositoryImpl implements UserRepository { @override Future getUser(String id) async { - return await remoteDataSource.getUser(id); + UserModel userModel = await remoteDataSource.getUser(id); + return userModel; // Retourne un UserModel qui est un sous-type de User + } + + Future authenticateUser(String email, String password) async { + UserModel userModel = await remoteDataSource.authenticateUser(email, password); + return userModel; // Retourne un UserModel qui est un sous-type de User } } diff --git a/lib/data/models/user_model.dart b/lib/data/models/user_model.dart index 2fd509e..a987f32 100644 --- a/lib/data/models/user_model.dart +++ b/lib/data/models/user_model.dart @@ -1,26 +1,37 @@ - -import '../../domain/entities/user.dart'; +import 'package:afterwork/domain/entities/user.dart'; class UserModel extends User { const UserModel({ - required super.id, - required super.name, - required super.email, - }); + required String id, + required String nom, + required String prenoms, + required String email, + required String motDePasse, + }) : super( + id: id, + nom: nom, + prenoms: prenoms, + email: email, + motDePasse: motDePasse, + ); factory UserModel.fromJson(Map json) { return UserModel( - id: json['id'], - name: json['name'], - email: json['email'], + id: json['id'] ?? '', + nom: json['nom'] ?? '', + prenoms: json['prenoms'] ?? '', + email: json['email'] ?? '', + motDePasse: json['motDePasse'] ?? '', ); } Map toJson() { return { 'id': id, - 'name': name, + 'nom': nom, + 'prenoms': prenoms, 'email': email, + 'motDePasse': motDePasse, }; } } diff --git a/lib/domain/entities/user.dart b/lib/domain/entities/user.dart index 1eed52c..5a25f95 100644 --- a/lib/domain/entities/user.dart +++ b/lib/domain/entities/user.dart @@ -2,11 +2,19 @@ import 'package:equatable/equatable.dart'; class User extends Equatable { final String id; - final String name; + final String nom; + final String prenoms; final String email; + final String motDePasse; - const User({required this.id, required this.name, required this.email}); + const User({ + required this.id, + required this.nom, + required this.prenoms, + required this.email, + required this.motDePasse, + }); @override - List get props => [id, name, email]; + List get props => [id, nom, prenoms, email, motDePasse]; } diff --git a/lib/presentation/screens/login/login_screen.dart b/lib/presentation/screens/login/login_screen.dart index 8ee1aa1..180f116 100644 --- a/lib/presentation/screens/login/login_screen.dart +++ b/lib/presentation/screens/login/login_screen.dart @@ -1,45 +1,22 @@ import 'package:flutter/material.dart'; +import 'package:afterwork/data/datasources/user_remote_data_source.dart'; +import 'package:afterwork/data/models/user_model.dart'; +import 'package:http/http.dart' as http; class LoginScreen extends StatefulWidget { - const LoginScreen({Key? key}) : super(key: key); + const LoginScreen({super.key}); @override _LoginScreenState createState() => _LoginScreenState(); } -class _LoginScreenState extends State with SingleTickerProviderStateMixin { +class _LoginScreenState extends State { final _formKey = GlobalKey(); - String _email = ''; - String _password = ''; + String _email = ''; // Initialisation par défaut + String _password = ''; // Initialisation par défaut bool _isPasswordVisible = false; - late AnimationController _animationController; - late Animation _slideAnimation; - - @override - void initState() { - super.initState(); - _animationController = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 500), - ); - - _slideAnimation = Tween( - begin: const Offset(0.0, 1.0), - end: Offset.zero, - ).animate(CurvedAnimation( - parent: _animationController, - curve: Curves.easeOut, - )); - - _animationController.forward(); - } - - @override - void dispose() { - _animationController.dispose(); - super.dispose(); - } + final UserRemoteDataSource _userRemoteDataSource = UserRemoteDataSource(http.Client()); void _togglePasswordVisibility() { setState(() { @@ -47,11 +24,32 @@ class _LoginScreenState extends State with SingleTickerProviderStat }); } - void _submit() { + void _submit() async { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); - print('Email: $_email, Password: $_password'); // Utilisation des valeurs - // Implémente la logique de connexion ici + + print('Email: $_email'); // Pour vérifier la valeur de l'email + print('Mot de passe: $_password'); // Pour vérifier la valeur du mot de passe + + if (_email.isEmpty || _password.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Veuillez remplir tous les champs')), + ); + return; + } + + try { + UserModel user = await _userRemoteDataSource.authenticateUser(_email, _password); + print('Connexion réussie : ${user.email}'); + // Naviguer vers la page d'accueil ou autre + } catch (e) { + print('Erreur lors de la connexion: $e'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(e.toString())), + ); + } + } else { + print('Formulaire invalide'); } } @@ -61,124 +59,117 @@ class _LoginScreenState extends State with SingleTickerProviderStat return Scaffold( backgroundColor: Colors.white, - body: Center( - child: SingleChildScrollView( - padding: const EdgeInsets.all(16.0), - child: SlideTransition( - position: _slideAnimation, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - // Logo - Image.asset( - 'lib/assets/images/logo.png', - height: size.height * 0.2, - ), - const SizedBox(height: 20), - const Text( - 'Bienvenue sur AfterWork', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.blueAccent, - ), - ), - const SizedBox(height: 40), - - // Formulaire de connexion - Form( - key: _formKey, - child: Column( - children: [ - // Champ Email - TextFormField( - decoration: const InputDecoration( - labelText: 'Email', - border: OutlineInputBorder(), - prefixIcon: Icon(Icons.email), - ), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre email'; - } - if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value)) { - return 'Veuillez entrer un email valide'; - } - return null; - }, - onSaved: (value) { - _email = value!; - }, - ), - const SizedBox(height: 20), - - // Champ Mot de passe - TextFormField( - decoration: InputDecoration( - labelText: 'Mot de passe', - border: const OutlineInputBorder(), - prefixIcon: const Icon(Icons.lock), - suffixIcon: IconButton( - icon: Icon( - _isPasswordVisible - ? Icons.visibility - : Icons.visibility_off, - ), - onPressed: _togglePasswordVisibility, - ), - ), - obscureText: !_isPasswordVisible, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre mot de passe'; - } - if (value.length < 6) { - return 'Le mot de passe doit comporter au moins 6 caractères'; - } - return null; - }, - onSaved: (value) { - _password = value!; - }, - ), - const SizedBox(height: 20), - - // Bouton de connexion - SizedBox( - width: double.infinity, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.all(16.0), - textStyle: const TextStyle(fontSize: 18), - backgroundColor: Colors.blueAccent, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - ), - onPressed: _submit, - child: const Text('Connexion'), - ), - ), - const SizedBox(height: 20), - - // Lien pour s'inscrire - TextButton( - onPressed: () { - // Naviguer vers la page d'inscription - }, - child: const Text( - 'Pas encore de compte ? Inscrivez-vous', - style: TextStyle(color: Colors.blueAccent), - ), - ), - ], - ), - ), - ], + body: Stack( + children: [ + // Arrière-plan + Positioned.fill( + child: Image.asset( + 'lib/assets/images/background.webp', // Remplace par le chemin de ton image + fit: BoxFit.cover, ), ), - ), + // Contenu de la page + Center( + child: SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + 'lib/assets/images/logo.png', + height: size.height * 0.2, + ), + const SizedBox(height: 20), + const Text( + 'Bienvenue sur AfterWork', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.blueAccent, + ), + ), + const SizedBox(height: 40), + TextFormField( + decoration: const InputDecoration( + labelText: 'Email', + border: OutlineInputBorder(), + prefixIcon: Icon(Icons.email), + ), + keyboardType: TextInputType.emailAddress, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Veuillez entrer votre email'; + } + if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value)) { + return 'Veuillez entrer un email valide'; + } + return null; + }, + onSaved: (value) { + _email = value ?? ''; // Utiliser une chaîne vide si value est null + }, + ), + const SizedBox(height: 20), + TextFormField( + decoration: InputDecoration( + labelText: 'Mot de passe', + border: const OutlineInputBorder(), + prefixIcon: const Icon(Icons.lock), + suffixIcon: IconButton( + icon: Icon( + _isPasswordVisible ? Icons.visibility : Icons.visibility_off, + ), + onPressed: _togglePasswordVisibility, + ), + ), + obscureText: !_isPasswordVisible, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Veuillez entrer votre mot de passe'; + } + if (value.length < 6) { + return 'Le mot de passe doit comporter au moins 6 caractères'; + } + return null; + }, + onSaved: (value) { + _password = value ?? ''; // Utiliser une chaîne vide si value est null + }, + ), + const SizedBox(height: 20), + SizedBox( + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.all(16.0), + textStyle: const TextStyle(fontSize: 18), + backgroundColor: Colors.blueAccent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + ), + onPressed: _submit, + child: const Text('Connexion'), + ), + ), + const SizedBox(height: 20), + TextButton( + onPressed: () { + // Naviguer vers la page d'inscription + }, + child: const Text( + 'Pas encore de compte ? Inscrivez-vous', + style: TextStyle(color: Colors.blueAccent), + ), + ), + ], + ), + ), + ), + ), + ], ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 5720137..8376ad8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,6 +39,7 @@ flutter: assets: - lib/assets/images/logo.png + - lib/assets/images/background.webp # To add assets to your application, add an assets section, like this: # assets: