import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import '../../../../l10n/app_localizations.dart'; import '../viewmodels/auth_viewmodel.dart'; class RegisterPage extends StatefulWidget { const RegisterPage({super.key}); @override State createState() => _RegisterPageState(); } class _RegisterPageState extends State { final _formKey = GlobalKey(); final _nameController = TextEditingController(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); final _confirmPasswordController = TextEditingController(); bool _obscurePassword = true; bool _obscureConfirmPassword = true; @override void dispose() { _nameController.dispose(); _emailController.dispose(); _passwordController.dispose(); _confirmPasswordController.dispose(); super.dispose(); } Future _register() async { if (!_formKey.currentState!.validate()) return; final viewModel = context.read(); final l10n = AppLocalizations.of(context)!; final success = await viewModel.register( email: _emailController.text.trim(), password: _passwordController.text, name: _nameController.text.trim(), ); if (mounted && success) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(l10n.registerSuccess)), ); context.go('/login'); } } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; return Scaffold( appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => context.go('/login'), ), ), body: SafeArea( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 400), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( l10n.register, style: Theme.of(context).textTheme.headlineMedium, textAlign: TextAlign.center, ), const SizedBox(height: 32), TextFormField( controller: _nameController, textCapitalization: TextCapitalization.words, textInputAction: TextInputAction.next, decoration: InputDecoration( labelText: l10n.name, prefixIcon: const Icon(Icons.person_outlined), border: const OutlineInputBorder(), ), validator: (value) { if (value == null || value.isEmpty) { return l10n.nameRequired; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: _emailController, keyboardType: TextInputType.emailAddress, autocorrect: false, textInputAction: TextInputAction.next, decoration: InputDecoration( labelText: l10n.email, prefixIcon: const Icon(Icons.email_outlined), border: const OutlineInputBorder(), ), validator: (value) { if (value == null || value.isEmpty) { return l10n.emailRequired; } if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$') .hasMatch(value)) { return l10n.emailInvalid; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: _passwordController, obscureText: _obscurePassword, textInputAction: TextInputAction.next, decoration: InputDecoration( labelText: l10n.password, prefixIcon: const Icon(Icons.lock_outlined), border: const OutlineInputBorder(), suffixIcon: SizedBox( width: 48, height: 48, child: IconButton( icon: Icon( _obscurePassword ? Icons.visibility_outlined : Icons.visibility_off_outlined, ), onPressed: () { setState(() => _obscurePassword = !_obscurePassword); }, ), ), ), validator: (value) { if (value == null || value.isEmpty) { return l10n.passwordRequired; } if (value.length < 8) { return l10n.passwordTooShort; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: _confirmPasswordController, obscureText: _obscureConfirmPassword, textInputAction: TextInputAction.done, onFieldSubmitted: (_) => _register(), decoration: InputDecoration( labelText: l10n.confirmPassword, prefixIcon: const Icon(Icons.lock_outlined), border: const OutlineInputBorder(), suffixIcon: SizedBox( width: 48, height: 48, child: IconButton( icon: Icon( _obscureConfirmPassword ? Icons.visibility_outlined : Icons.visibility_off_outlined, ), onPressed: () { setState(() => _obscureConfirmPassword = !_obscureConfirmPassword); }, ), ), ), validator: (value) { if (value != _passwordController.text) { return l10n.passwordsDoNotMatch; } return null; }, ), const SizedBox(height: 8), Consumer( builder: (context, viewModel, _) { if (viewModel.error != null) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Text( viewModel.error!, style: TextStyle( color: Theme.of(context).colorScheme.error, ), textAlign: TextAlign.center, ), ); } return const SizedBox.shrink(); }, ), const SizedBox(height: 16), Consumer( builder: (context, viewModel, child) { return SizedBox( height: 56, child: FilledButton( onPressed: viewModel.isLoading ? null : _register, child: viewModel.isLoading ? const SizedBox( width: 24, height: 24, child: CircularProgressIndicator( strokeWidth: 2, ), ) : Text(l10n.register), ), ); }, ), const SizedBox(height: 24), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(l10n.alreadyHaveAccount), TextButton( onPressed: () => context.go('/login'), child: Text(l10n.login), ), ], ), ], ), ), ), ), ), ), ); } }