import 'package:flutter/material.dart'; import 'package:frontend/api_services/api_services.dart'; class UserListPage extends StatefulWidget { @override _UserListPageState createState() => _UserListPageState(); } class _UserListPageState extends State { final ApiService apiService = ApiService(); List> users = []; bool isLoading = true; final _formKey = GlobalKey(); final _nameController = TextEditingController(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); final _alamatController = TextEditingController(); final _nomorTeleponController = TextEditingController(); @override void initState() { super.initState(); _loadUsers(); } @override void dispose() { // Dispose controllers in dispose method _nameController.dispose(); _emailController.dispose(); _passwordController.dispose(); _alamatController.dispose(); _nomorTeleponController.dispose(); super.dispose(); } Future _addUser() async { try { await apiService.registerUser( name: _nameController.text, email: _emailController.text, password: _passwordController.text, alamat: _alamatController.text, nomorTelepon: _nomorTeleponController.text, ); // Clear form _nameController.clear(); _emailController.clear(); _passwordController.clear(); _alamatController.clear(); _nomorTeleponController.clear(); // Refresh user list await _loadUsers(); // Show success message ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('User berhasil ditambahkan'), backgroundColor: Colors.green, ), ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Gagal menambahkan user: ${e.toString()}'), backgroundColor: Colors.red, ), ); } } Future _updateUser(Map user) async { try { // Hanya kirim password jika diisi String? newPassword = _passwordController.text.isEmpty ? null : _passwordController.text; await apiService.updateUser( id: user['id'], name: _nameController.text, email: _emailController.text, password: newPassword, // Kirim null jika password kosong alamat: _alamatController.text, nomorTelepon: _nomorTeleponController.text, ); // Clear form _nameController.clear(); _emailController.clear(); _passwordController.clear(); _alamatController.clear(); _nomorTeleponController.clear(); // Refresh user list await _loadUsers(); // Show success message with password info ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( newPassword != null ? 'User berhasil diperbarui termasuk password' : 'User berhasil diperbarui', ), backgroundColor: Colors.green, ), ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Gagal memperbarui user: ${e.toString()}'), backgroundColor: Colors.red, ), ); } } Future _deleteUser(int userId) async { try { await apiService.deleteUser(userId); await _loadUsers(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('User berhasil dihapus'), backgroundColor: Colors.green, ), ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Gagal menghapus user: ${e.toString()}'), backgroundColor: Colors.red, ), ); } } void _showDeleteConfirmation(Map user) { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Konfirmasi Hapus'), content: Text( 'Apakah Anda yakin ingin menghapus user ${user['name']}?', ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('Batal'), ), ElevatedButton( onPressed: () async { try { Navigator.pop(context); // Close dialog first await apiService.deleteUser(user['id']); await _loadUsers(); // Refresh the list ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('User berhasil dihapus'), backgroundColor: Colors.green, ), ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Gagal menghapus user: ${e.toString()}'), backgroundColor: Colors.red, ), ); } }, style: ElevatedButton.styleFrom(backgroundColor: Colors.red), child: Text('Hapus'), ), ], ), ); } void _showUpdateDialog(Map user) { // Pre-fill form with existing user data _nameController.text = user['name'] ?? ''; _emailController.text = user['email'] ?? ''; _alamatController.text = user['alamat'] ?? ''; _nomorTeleponController.text = user['nomorTelepon'] ?? ''; _passwordController.text = ''; // Empty for security showDialog( context: context, builder: (context) => AlertDialog( title: Text('Update User'), content: SingleChildScrollView( child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ TextFormField( controller: _nameController, decoration: InputDecoration(labelText: 'Nama'), validator: (value) => value?.isEmpty ?? true ? 'Nama tidak boleh kosong' : null, ), TextFormField( controller: _emailController, decoration: InputDecoration(labelText: 'Email'), validator: (value) { if (value?.isEmpty ?? true) return 'Email tidak boleh kosong'; if (!value!.contains('@')) return 'Email tidak valid'; return null; }, ), TextFormField( controller: _passwordController, decoration: InputDecoration( labelText: 'Password Baru', helperText: 'Kosongkan jika tidak ingin mengubah password', ), obscureText: true, validator: (value) { if (value?.isNotEmpty ?? false) { if (value!.length < 6) return 'Password minimal 6 karakter'; } return null; }, ), TextFormField( controller: _alamatController, decoration: InputDecoration(labelText: 'Alamat'), validator: (value) => value?.isEmpty ?? true ? 'Alamat tidak boleh kosong' : null, ), TextFormField( controller: _nomorTeleponController, decoration: InputDecoration(labelText: 'Nomor Telepon'), keyboardType: TextInputType.phone, validator: (value) => value?.isEmpty ?? true ? 'Nomor telepon tidak boleh kosong' : null, ), ], ), ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('Batal'), ), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { Navigator.pop(context); _updateUser(user); } }, style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF9DC08D), ), child: Text('Update'), ), ], ), ); } void _showAddUserDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Tambah User Baru'), content: SingleChildScrollView( child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ TextFormField( controller: _nameController, decoration: InputDecoration(labelText: 'Nama'), validator: (value) { if (value == null || value.isEmpty) { return 'Nama tidak boleh kosong'; } return null; }, ), TextFormField( controller: _emailController, decoration: InputDecoration(labelText: 'Email'), validator: (value) { if (value == null || value.isEmpty) { return 'Email tidak boleh kosong'; } if (!value.contains('@')) { return 'Email tidak valid'; } return null; }, ), TextFormField( controller: _passwordController, decoration: InputDecoration(labelText: 'Password'), obscureText: true, validator: (value) { if (value == null || value.isEmpty) { return 'Password tidak boleh kosong'; } if (value.length < 6) { return 'Password minimal 6 karakter'; } return null; }, ), TextFormField( controller: _alamatController, decoration: InputDecoration(labelText: 'Alamat'), validator: (value) { if (value == null || value.isEmpty) { return 'Alamat tidak boleh kosong'; } return null; }, ), TextFormField( controller: _nomorTeleponController, decoration: InputDecoration(labelText: 'Nomor Telepon'), keyboardType: TextInputType.phone, validator: (value) { if (value == null || value.isEmpty) { return 'Nomor telepon tidak boleh kosong'; } return null; }, ), ], ), ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('Batal'), ), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { Navigator.pop(context); _addUser(); } }, style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF9DC08D), ), child: Text('Simpan'), ), ], ), ); } Future _loadUsers() async { try { final userList = await apiService.getUsers(); setState(() { users = userList; isLoading = false; }); } catch (e) { print('Error loading users: $e'); setState(() { isLoading = false; }); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Daftar Pengguna'), backgroundColor: Color(0xFF9DC08D), ), floatingActionButton: FloatingActionButton( onPressed: _showAddUserDialog, backgroundColor: Color(0xFF9DC08D), child: Icon(Icons.add), ), body: isLoading ? Center(child: CircularProgressIndicator()) : SingleChildScrollView( scrollDirection: Axis.horizontal, child: SingleChildScrollView( child: DataTable( columnSpacing: 20, columns: [ DataColumn(label: Text('Nama')), DataColumn(label: Text('Email')), DataColumn(label: Text('Alamat')), DataColumn(label: Text('No. Telepon')), DataColumn(label: Text('Role')), DataColumn(label: Text('Aksi')), ], rows: users.map((user) { return DataRow( cells: [ DataCell(Text(user['name'] ?? '-')), DataCell(Text(user['email'] ?? '-')), DataCell(Text(user['alamat'] ?? '-')), DataCell(Text(user['nomorTelepon'] ?? '-')), DataCell( Container( padding: EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: user['role'] == 'admin' ? Colors.blue.withOpacity(0.2) : Colors.green.withOpacity(0.2), borderRadius: BorderRadius.circular(12), ), child: Text( user['role'] ?? 'user', style: TextStyle( color: user['role'] == 'admin' ? Colors.blue : Colors.green, ), ), ), ), DataCell( Row( children: [ IconButton( icon: Icon(Icons.edit), onPressed: () => _showUpdateDialog(user), ), IconButton( icon: Icon( Icons.delete, color: Colors.red, ), onPressed: () => _showDeleteConfirmation(user), ), ], ), ), ], ); }).toList(), ), ), ), ); } }