Modifs MVVM
This commit is contained in:
@ -1,8 +1,7 @@
|
||||
import 'package:em2rp/providers/local_auth_provider.dart';
|
||||
import 'package:em2rp/providers/local_user_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:em2rp/views/widgets/nav/main_drawer.dart';
|
||||
import 'package:provider/provider.dart'; // Import Provider
|
||||
import 'package:em2rp/providers/user_provider.dart'; // Import UserProvider
|
||||
import 'package:em2rp/utils/colors.dart';
|
||||
|
||||
class CalendarPage extends StatelessWidget {
|
||||
@ -10,7 +9,7 @@ class CalendarPage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final localAuthProvider = Provider.of<LocalAuthProvider>(context);
|
||||
final localAuthProvider = Provider.of<LocalUserProvider>(context);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Calendrier')),
|
||||
|
@ -1,240 +1,106 @@
|
||||
import 'package:em2rp/providers/local_auth_provider.dart';
|
||||
import 'package:em2rp/providers/user_provider.dart';
|
||||
import 'package:em2rp/utils/firebase_storage_manager.dart';
|
||||
import 'package:em2rp/providers/local_user_provider.dart';
|
||||
import 'package:em2rp/providers/users_provider.dart';
|
||||
import 'package:em2rp/views/widgets/image/profile_picture.dart';
|
||||
import 'package:em2rp/views/widgets/nav/main_drawer.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:em2rp/views/widgets/inputs/styled_text_field.dart';
|
||||
|
||||
class MyAccountPage extends StatefulWidget {
|
||||
class MyAccountPage extends StatelessWidget {
|
||||
const MyAccountPage({super.key});
|
||||
@override
|
||||
_MyAccountPageState createState() => _MyAccountPageState();
|
||||
}
|
||||
|
||||
class _MyAccountPageState extends State<MyAccountPage> {
|
||||
final User? user = FirebaseAuth.instance.currentUser;
|
||||
final TextEditingController _firstNameController = TextEditingController();
|
||||
final TextEditingController _lastNameController = TextEditingController();
|
||||
final TextEditingController _phoneController = TextEditingController();
|
||||
String? profilePhotoUrl;
|
||||
bool _isHoveringProfilePic = false;
|
||||
final FirebaseStorageManager _storageManager =
|
||||
FirebaseStorageManager(); // Instance of FirebaseStorageManager
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadUserData();
|
||||
}
|
||||
|
||||
Future<void> _loadUserData() async {
|
||||
if (user != null) {
|
||||
DocumentSnapshot userData = await FirebaseFirestore.instance
|
||||
.collection('users')
|
||||
.doc(user!.uid)
|
||||
.get();
|
||||
|
||||
if (userData.exists) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_firstNameController.text = userData['firstName'] ?? '';
|
||||
_lastNameController.text = userData['lastName'] ?? '';
|
||||
_phoneController.text = userData['phone'] ?? '';
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _updateUserData() async {
|
||||
if (user != null) {
|
||||
try {
|
||||
await FirebaseFirestore.instance.collection('users').doc(user!.uid).set(
|
||||
{
|
||||
'firstName': _firstNameController.text,
|
||||
'lastName': _lastNameController.text,
|
||||
'phone': _phoneController.text,
|
||||
},
|
||||
SetOptions(merge: true),
|
||||
);
|
||||
|
||||
// **MISE À JOUR DU USERPROVIDER APRÈS SUCCÈS**
|
||||
final userProvider = Provider.of<UserProvider>(context, listen: false);
|
||||
userProvider.setUserFirstName(_firstNameController.text);
|
||||
userProvider.setUserLastName(_lastNameController.text);
|
||||
userProvider.setUserPhoneNumber(_phoneController.text);
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content:
|
||||
Text('Informations personnelles mises à jour avec succès!'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'Erreur lors de la mise à jour des informations personnelles: ${e.toString()}',
|
||||
),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
print(
|
||||
'Erreur lors de la mise à jour des informations utilisateur: ${e.toString()}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _changeProfilePicture() async {
|
||||
final ImagePicker picker = ImagePicker();
|
||||
final XFile? image = await picker.pickImage(
|
||||
source: ImageSource.gallery,
|
||||
); // You can also use ImageSource.camera
|
||||
|
||||
if (image != null) {
|
||||
// Call FirebaseStorageManager to send the profile picture
|
||||
String? newProfilePhotoUrl = await _storageManager.sendProfilePicture(
|
||||
imageFile: image,
|
||||
uid: user!.uid,
|
||||
);
|
||||
if (newProfilePhotoUrl != null) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
profilePhotoUrl =
|
||||
newProfilePhotoUrl; // Update the profilePhotoUrl to refresh the UI
|
||||
});
|
||||
// Optionally, update the UserProvider if you are using it to manage user data globally
|
||||
// Provider.of<UserProvider>(context, listen: false).setUserProfilePhotoUrl(newProfilePhotoUrl);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Photo de profil mise à jour avec succès!'),
|
||||
backgroundColor: Colors.green, // Optional: Style for success
|
||||
),
|
||||
);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text(
|
||||
'Erreur lors de la mise à jour de la photo de profil.',
|
||||
),
|
||||
backgroundColor: Colors.red, // Optional: Style for error
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// User cancelled image picking
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Sélection de photo annulée.')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final localAuthProvider = Provider.of<LocalAuthProvider>(
|
||||
context,
|
||||
); // Get UserProvider instance
|
||||
|
||||
return Scaffold(
|
||||
appBar:
|
||||
AppBar(title: const Text('Mon Compte')), // More user-friendly title
|
||||
drawer: MainDrawer(
|
||||
currentPage: '/my_account'), // Pass UserProvider to MainDrawer
|
||||
body: SingleChildScrollView(
|
||||
// Added SingleChildScrollView for better responsiveness
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(
|
||||
24.0), // Increased padding around the main content
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
MouseRegion(
|
||||
onEnter: (_) => setState(() => _isHoveringProfilePic = true),
|
||||
onExit: (_) => setState(() => _isHoveringProfilePic = false),
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap:
|
||||
_changeProfilePicture, // Call _changeProfilePicture on tap
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
ProfilePictureWidget(
|
||||
userId: user!.uid,
|
||||
radius:
|
||||
80), // Increased radius for larger profile picture
|
||||
if (_isHoveringProfilePic)
|
||||
Container(
|
||||
width: 160, // Slightly larger hover overlay
|
||||
height: 160,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black54,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Center(
|
||||
child: Icon(
|
||||
Icons.edit,
|
||||
color: Colors.white,
|
||||
size: 36, // Slightly larger edit icon
|
||||
),
|
||||
appBar: AppBar(title: const Text('Mon Compte')),
|
||||
drawer: MainDrawer(currentPage: '/my_account'),
|
||||
body: Consumer<LocalUserProvider>(
|
||||
builder: (context, userProvider, child) {
|
||||
final user = userProvider.currentUser;
|
||||
final usersProvider = context.read<UsersProvider>();
|
||||
|
||||
if (user == null) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
final firstNameController =
|
||||
TextEditingController(text: user.firstName);
|
||||
final lastNameController = TextEditingController(text: user.lastName);
|
||||
final phoneController = TextEditingController(text: user.phoneNumber);
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
GestureDetector(
|
||||
//onTap: () => userProvider.changeProfilePicture(); TODO
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
ProfilePictureWidget(
|
||||
userId: user.uid,
|
||||
radius: 80,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: Card(
|
||||
elevation: 4.0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 500),
|
||||
child: Column(
|
||||
children: [
|
||||
StyledTextField(
|
||||
labelText: 'Prénom',
|
||||
controller: firstNameController,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
StyledTextField(
|
||||
labelText: 'Nom',
|
||||
controller: lastNameController,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
StyledTextField(
|
||||
labelText: 'Numéro de téléphone',
|
||||
controller: phoneController,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
StyledTextField(
|
||||
labelText: 'Email',
|
||||
controller:
|
||||
TextEditingController(text: user.email),
|
||||
enabled: false,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
userProvider.updateUserData(
|
||||
firstName: firstNameController.text,
|
||||
lastName: lastNameController.text,
|
||||
phoneNumber: phoneController.text,
|
||||
);
|
||||
},
|
||||
child: const Text('Enregistrer'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: Card(
|
||||
elevation: 4.0, // Ajouter un léger relief
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(12.0)), // Bords arrondis
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(
|
||||
24.0), // Padding intérieur de la carte
|
||||
child: ConstrainedBox(
|
||||
// Limiter la largeur des inputs dans la carte
|
||||
constraints: BoxConstraints(
|
||||
maxWidth:
|
||||
500), // Ajustez la largeur maximale souhaitée
|
||||
child: Column(
|
||||
children: [
|
||||
StyledTextField(
|
||||
labelText: 'Prénom',
|
||||
controller: _firstNameController),
|
||||
const SizedBox(height: 16),
|
||||
StyledTextField(
|
||||
labelText: 'Nom',
|
||||
controller: _lastNameController),
|
||||
const SizedBox(height: 16),
|
||||
StyledTextField(
|
||||
labelText: 'Numéro de téléphone',
|
||||
controller: _phoneController),
|
||||
const SizedBox(height: 16),
|
||||
StyledTextField(
|
||||
labelText: 'Email',
|
||||
controller:
|
||||
TextEditingController(text: user?.email ?? ''),
|
||||
enabled: false,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: _updateUserData,
|
||||
child: const Text('Enregistrer'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1,15 +1,14 @@
|
||||
import 'package:em2rp/providers/local_auth_provider.dart';
|
||||
import 'package:em2rp/providers/local_user_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../view_model/user_management_view_model.dart';
|
||||
|
||||
class UserManagementPage extends StatelessWidget {
|
||||
const UserManagementPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final userViewModel = Provider.of<UserManagementViewModel>(context);
|
||||
final authProvider = Provider.of<LocalAuthProvider>(context);
|
||||
// final userViewModel = Provider.of<UserManagementViewModel>(context);
|
||||
final authProvider = Provider.of<LocalUserProvider>(context);
|
||||
|
||||
if (authProvider.role != 'ADMIN') {
|
||||
return Scaffold(
|
||||
@ -22,46 +21,46 @@ class UserManagementPage extends StatelessWidget {
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Gestion des Utilisateurs')),
|
||||
body: userViewModel.isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: ListView.builder(
|
||||
itemCount: userViewModel.users.length,
|
||||
itemBuilder: (context, index) {
|
||||
final user = userViewModel.users[index];
|
||||
return ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: NetworkImage(user.profilePhotoUrl)),
|
||||
title: Text('${user.firstName} ${user.lastName}'),
|
||||
subtitle: Text(user.email),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
onPressed: () {
|
||||
// Afficher la pop-up d'édition
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.lock_reset),
|
||||
onPressed: () =>
|
||||
userViewModel.resetPassword(user.email),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete, color: Colors.red),
|
||||
onPressed: () => userViewModel.deleteUser(user.uid),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
// Ajouter un utilisateur
|
||||
},
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
// body: userViewModel.isLoading
|
||||
// ? const Center(child: CircularProgressIndicator())
|
||||
// : ListView.builder(
|
||||
// itemCount: userViewModel.users.length,
|
||||
// itemBuilder: (context, index) {
|
||||
// final user = userViewModel.users[index];
|
||||
// return ListTile(
|
||||
// leading: CircleAvatar(
|
||||
// backgroundImage: NetworkImage(user.profilePhotoUrl)),
|
||||
// title: Text('${user.firstName} ${user.lastName}'),
|
||||
// subtitle: Text(user.email),
|
||||
// trailing: Row(
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.edit),
|
||||
// onPressed: () {
|
||||
// // Afficher la pop-up d'édition
|
||||
// },
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.lock_reset),
|
||||
// onPressed: () =>
|
||||
// userViewModel.resetPassword(user.email),
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.delete, color: Colors.red),
|
||||
// onPressed: () => userViewModel.deleteUser(user.uid),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// floatingActionButton: FloatingActionButton(
|
||||
// onPressed: () {
|
||||
// // Ajouter un utilisateur
|
||||
// },
|
||||
// child: const Icon(Icons.add),
|
||||
// ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:em2rp/providers/local_auth_provider.dart';
|
||||
import 'package:em2rp/providers/local_user_provider.dart';
|
||||
import 'package:em2rp/utils/colors.dart';
|
||||
import 'package:em2rp/views/calendar_page.dart';
|
||||
import 'package:em2rp/views/my_account_page.dart';
|
||||
@ -14,7 +14,7 @@ class MainDrawer extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<LocalAuthProvider>(
|
||||
return Consumer<LocalUserProvider>(
|
||||
builder: (context, userProvider, child) {
|
||||
final hasUser = userProvider.currentUser != null;
|
||||
|
||||
|
Reference in New Issue
Block a user