environment_monitoring_app/lib/screens/register.dart

227 lines
9.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:provider/provider.dart';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:environment_monitoring_app/services/api_service.dart';
import 'package:environment_monitoring_app/auth_provider.dart';
class RegisterScreen extends StatefulWidget {
const RegisterScreen({super.key});
@override
State<RegisterScreen> createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
final _formKey = GlobalKey<FormState>();
// FIX: Removed direct instantiation of ApiService
bool _isLoading = false;
String _errorMessage = '';
// Controllers for text fields
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _firstNameController = TextEditingController();
final TextEditingController _lastNameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final TextEditingController _confirmPasswordController = TextEditingController();
final TextEditingController _phoneController = TextEditingController();
// State for dropdown selections
int? _selectedDepartmentId;
int? _selectedCompanyId;
int? _selectedPositionId;
@override
void dispose() {
_usernameController.dispose();
_firstNameController.dispose();
_lastNameController.dispose();
_emailController.dispose();
_passwordController.dispose();
_confirmPasswordController.dispose();
_phoneController.dispose();
super.dispose();
}
Future<void> _register() async {
if (!_formKey.currentState!.validate()) {
return;
}
setState(() {
_isLoading = true;
_errorMessage = '';
});
// FIX: Retrieve ApiService from the Provider tree
final apiService = Provider.of<ApiService>(context, listen: false);
final connectivityResult = await Connectivity().checkConnectivity();
if (connectivityResult == ConnectivityResult.none) {
if (!mounted) return;
setState(() {
_isLoading = false;
_errorMessage = 'An internet connection is required to register.';
});
_showSnackBar(_errorMessage, isError: true);
return;
}
final result = await apiService.register( // FIX: Use retrieved instance
username: _usernameController.text.trim(),
firstName: _firstNameController.text.trim(),
lastName: _lastNameController.text.trim(),
email: _emailController.text.trim(),
password: _passwordController.text.trim(),
phoneNumber: _phoneController.text.trim(),
departmentId: _selectedDepartmentId,
companyId: _selectedCompanyId,
positionId: _selectedPositionId,
);
if (!mounted) return;
if (result['success'] == true) {
_showSnackBar('Registration successful! Please log in.', isError: false);
Navigator.of(context).pop();
} else {
setState(() {
_isLoading = false;
_errorMessage = result['message'] ?? 'An unknown registration error occurred.';
});
_showSnackBar(_errorMessage, isError: true);
}
}
void _showSnackBar(String message, {bool isError = false}) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: isError ? Theme.of(context).colorScheme.error : Colors.green,
),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Register')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
// Use a Consumer to rebuild the form when the provider's data changes
child: Consumer<AuthProvider>(
builder: (context, auth, child) {
// Access the cached data from the listening AuthProvider
final departments = auth.departments ?? [];
final companies = auth.companies ?? [];
final positions = auth.positions ?? [];
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(labelText: 'Username *'),
validator: (value) => value!.isEmpty ? 'Username is required' : null,
),
const SizedBox(height: 16),
TextFormField(
controller: _firstNameController,
decoration: const InputDecoration(labelText: 'First Name'),
),
const SizedBox(height: 16),
TextFormField(
controller: _lastNameController,
decoration: const InputDecoration(labelText: 'Last Name'),
),
const SizedBox(height: 16),
TextFormField(
controller: _emailController,
decoration: const InputDecoration(labelText: 'Email *'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) return 'Email is required';
if (!RegExp(r'\S+@\S+\.\S+').hasMatch(value)) return 'Please enter a valid email';
return null;
},
),
const SizedBox(height: 16),
TextFormField(
controller: _passwordController,
decoration: const InputDecoration(labelText: 'Password *'),
obscureText: true,
validator: (value) => (value?.length ?? 0) < 6 ? 'Password must be at least 6 characters' : null,
),
const SizedBox(height: 16),
TextFormField(
controller: _confirmPasswordController,
decoration: const InputDecoration(labelText: 'Confirm Password *'),
obscureText: true,
validator: (value) {
if (value != _passwordController.text) return 'Passwords do not match';
return null;
},
),
const SizedBox(height: 16),
TextFormField(
controller: _phoneController,
decoration: const InputDecoration(labelText: 'Phone Number'),
keyboardType: TextInputType.phone,
),
const SizedBox(height: 16),
DropdownSearch<Map<String, dynamic>>(
items: departments,
itemAsString: (item) => item['department_name'],
onChanged: (value) => setState(() => _selectedDepartmentId = value?['department_id']),
popupProps: const PopupProps.menu(showSearchBox: true),
dropdownDecoratorProps: const DropDownDecoratorProps(dropdownSearchDecoration: InputDecoration(labelText: "Department")),
),
const SizedBox(height: 16),
DropdownSearch<Map<String, dynamic>>(
items: companies,
itemAsString: (item) => item['company_name'],
onChanged: (value) => setState(() => _selectedCompanyId = value?['company_id']),
popupProps: const PopupProps.menu(showSearchBox: true),
dropdownDecoratorProps: const DropDownDecoratorProps(dropdownSearchDecoration: InputDecoration(labelText: "Company")),
),
const SizedBox(height: 16),
DropdownSearch<Map<String, dynamic>>(
items: positions,
itemAsString: (item) => item['position_name'],
onChanged: (value) => setState(() => _selectedPositionId = value?['position_id']),
popupProps: const PopupProps.menu(showSearchBox: true),
dropdownDecoratorProps: const DropDownDecoratorProps(dropdownSearchDecoration: InputDecoration(labelText: "Position")),
),
const SizedBox(height: 24),
_isLoading
? const CircularProgressIndicator()
: ElevatedButton(
onPressed: _register,
style: ElevatedButton.styleFrom(
minimumSize: const Size(double.infinity, 50),
),
child: const Text('Register'),
),
if (_errorMessage.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 12),
child: Text(
_errorMessage,
style: TextStyle(color: Theme.of(context).colorScheme.error),
textAlign: TextAlign.center,
),
),
],
),
);
},
),
),
);
}
}