import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../core/providers/auth_provider.dart'; import '../../core/router/app_router.dart'; import '../../core/theme/app_theme.dart'; import '../../core/widgets/tooth_logo.dart'; import 'auth_widgets.dart'; class SignUpScreen extends ConsumerStatefulWidget { const SignUpScreen({super.key}); @override ConsumerState createState() => _SignUpScreenState(); } class _SignUpScreenState extends ConsumerState { final _formKey = GlobalKey(); final _firstNameCtrl = TextEditingController(); final _lastNameCtrl = TextEditingController(); final _emailCtrl = TextEditingController(); final _passCtrl = TextEditingController(); final _confirmPassCtrl = TextEditingController(); bool _obscure = true; bool _obscureConfirm = true; bool _loading = false; String? _error; @override void dispose() { _firstNameCtrl.dispose(); _lastNameCtrl.dispose(); _emailCtrl.dispose(); _passCtrl.dispose(); _confirmPassCtrl.dispose(); super.dispose(); } Future _submit() async { if (!_formKey.currentState!.validate()) return; setState(() { _loading = true; _error = null; }); try { await ref.read(authProvider.notifier).register( email: _emailCtrl.text.trim(), password: _passCtrl.text, firstName: _firstNameCtrl.text.trim(), lastName: _lastNameCtrl.text.trim(), ); } catch (e) { setState(() { _error = _parseError(e.toString()); _loading = false; }); } } String _parseError(String msg) { if (msg.contains('already') || msg.contains('unique') || msg.contains('UNIQUE')) { return 'Bu e-posta adresi zaten kayıtlı.'; } if (msg.contains('403') || msg.contains('Forbidden')) { return 'Kayıt şu anda kapalı. Lütfen yönetici ile iletişime geçin.'; } return 'Kayıt olunamadı. Lütfen tekrar deneyin.'; } @override Widget build(BuildContext context) { final isDesktop = MediaQuery.sizeOf(context).width > 800; return Scaffold( backgroundColor: AppColors.background, body: isDesktop ? _buildDesktop(context) : _buildMobile(context), ); } // ── Mobile layout ────────────────────────────────────────────────────────── Widget _buildMobile(BuildContext context) { return SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24), child: _buildForm(context, isMobile: true), ), ); } // ── Desktop layout ───────────────────────────────────────────────────────── Widget _buildDesktop(BuildContext context) { return Row( children: [ // LEFT PANEL — solid gradient + white animated blobs on top Expanded( flex: 5, child: Stack( fit: StackFit.expand, children: [ Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [AppColors.primary, Color(0xFF1A5C8A)], ), ), ), const AnimatedAuthBg(bright: true), Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 56), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 72, height: 72, decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(20), border: Border.all( color: Colors.white.withValues(alpha: 0.3), width: 1.5, ), ), child: const Center(child: ToothLogo(size: 38, color: Colors.white)), ), const SizedBox(height: 24), const Text( 'DLS', style: TextStyle( fontSize: 48, fontWeight: FontWeight.w800, color: Colors.white, letterSpacing: 2, ), ), const SizedBox(height: 4), Text( 'Dental Lab Sistemi', style: TextStyle( fontSize: 17, color: Colors.white.withValues(alpha: 0.7), fontWeight: FontWeight.w500, ), ), const SizedBox(height: 48), const _FeatureBullet( icon: Icons.dashboard_rounded, text: 'İş takibi tek ekranda', ), const SizedBox(height: 16), const _FeatureBullet( icon: Icons.link_rounded, text: 'Klinik-lab bağlantısı', ), const SizedBox(height: 16), const _FeatureBullet( icon: Icons.bolt_rounded, text: 'Gerçek zamanlı durum', ), ], ), ), ), ], ), ), // RIGHT PANEL — light gray so white card stands out Container( width: 480, color: AppColors.background, child: SafeArea( child: LayoutBuilder( builder: (context, constraints) => SingleChildScrollView( child: ConstrainedBox( constraints: BoxConstraints(minHeight: constraints.maxHeight), child: IntrinsicHeight( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 32), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [_buildForm(context, isMobile: false)], ), ), ), ), ), ), ), ), ], ); } // ── Shared form content ──────────────────────────────────────────────────── Widget _buildForm(BuildContext context, {required bool isMobile}) { return Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (isMobile) const SizedBox(height: 48), // ── Back button + branding (mobile only) ─────────────────────── if (isMobile) ...[ Row( children: [ IconButton( onPressed: () => context.go(routeSignIn), icon: const Icon(Icons.arrow_back_ios_new_rounded, size: 20), style: IconButton.styleFrom( foregroundColor: AppColors.textPrimary, backgroundColor: AppColors.surface, padding: const EdgeInsets.all(10), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: const BorderSide(color: AppColors.border), ), ), ), ], ).animate().fadeIn(duration: 300.ms), const SizedBox(height: 28), Center( child: Column( children: [ Container( width: 72, height: 72, decoration: BoxDecoration( gradient: const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [AppColors.primary, AppColors.accent], ), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: AppColors.accent.withValues(alpha: 0.3), blurRadius: 18, offset: const Offset(0, 6), ), ], ), child: const Icon( Icons.person_add_alt_1_rounded, size: 32, color: Colors.white, ), ), const SizedBox(height: 16), const Text( 'Hesap Oluştur', style: TextStyle( fontSize: 26, fontWeight: FontWeight.w800, color: AppColors.textPrimary, ), ), const SizedBox(height: 4), const Text( 'DLS ağına katılın', style: TextStyle( fontSize: 14, color: AppColors.textSecondary, fontWeight: FontWeight.w500, ), ), ], ), ).animate().fadeIn(duration: 400.ms).slideY(begin: -0.08, end: 0), const SizedBox(height: 32), ], // Desktop back button (outside card) if (!isMobile) ...[ Row( children: [ IconButton( onPressed: () => context.go(routeSignIn), icon: const Icon(Icons.arrow_back_ios_new_rounded, size: 18), style: IconButton.styleFrom( foregroundColor: AppColors.textPrimary, backgroundColor: AppColors.surface, padding: const EdgeInsets.all(8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), side: const BorderSide(color: AppColors.border), ), ), ), ], ).animate().fadeIn(duration: 300.ms), const SizedBox(height: 20), ], // ── Form card ────────────────────────────────────────────────── Container( padding: EdgeInsets.all(isMobile ? 24 : 32), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(20), border: Border.all(color: AppColors.border), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: isMobile ? 0.05 : 0.09), blurRadius: isMobile ? 16 : 28, spreadRadius: 0, offset: const Offset(0, 4), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Heading inside card on desktop if (!isMobile) ...[ const Text( 'Hesap Oluştur', style: TextStyle( fontSize: 24, fontWeight: FontWeight.w800, color: AppColors.textPrimary, ), ).animate().fadeIn(duration: 400.ms).slideY(begin: -0.08, end: 0), const SizedBox(height: 4), const Text( 'DLS ağına katılın', style: TextStyle(fontSize: 14, color: AppColors.textSecondary), ).animate(delay: 40.ms).fadeIn(duration: 400.ms), const SizedBox(height: 24), ], // Ad / Soyad satırı Row( children: [ Expanded( child: _Field( controller: _firstNameCtrl, label: 'Ad', icon: Icons.badge_outlined, textCapitalization: TextCapitalization.words, textInputAction: TextInputAction.next, validator: (v) => (v == null || v.trim().isEmpty) ? 'Gerekli' : null, ), ), const SizedBox(width: 12), Expanded( child: _Field( controller: _lastNameCtrl, label: 'Soyad', icon: Icons.badge_outlined, textCapitalization: TextCapitalization.words, textInputAction: TextInputAction.next, validator: (v) => (v == null || v.trim().isEmpty) ? 'Gerekli' : null, ), ), ], ), const SizedBox(height: 12), _Field( controller: _emailCtrl, label: 'E-posta', icon: Icons.email_outlined, keyboardType: TextInputType.emailAddress, textInputAction: TextInputAction.next, validator: (v) { if (v == null || v.trim().isEmpty) return 'E-posta gereklidir'; if (!v.contains('@')) return 'Geçerli bir e-posta girin'; return null; }, ), const SizedBox(height: 12), _Field( controller: _passCtrl, label: 'Şifre', icon: Icons.lock_outline_rounded, obscureText: _obscure, textInputAction: TextInputAction.next, suffixIcon: IconButton( icon: Icon( _obscure ? Icons.visibility_outlined : Icons.visibility_off_outlined, size: 20, color: AppColors.textSecondary, ), onPressed: () => setState(() => _obscure = !_obscure), ), validator: (v) { if (v == null || v.isEmpty) return 'Şifre gereklidir'; if (v.length < 8) return 'En az 8 karakter olmalıdır'; return null; }, ), const SizedBox(height: 12), _Field( controller: _confirmPassCtrl, label: 'Şifre Tekrar', icon: Icons.lock_outline_rounded, obscureText: _obscureConfirm, textInputAction: TextInputAction.done, onFieldSubmitted: (_) => _submit(), suffixIcon: IconButton( icon: Icon( _obscureConfirm ? Icons.visibility_outlined : Icons.visibility_off_outlined, size: 20, color: AppColors.textSecondary, ), onPressed: () => setState(() => _obscureConfirm = !_obscureConfirm), ), validator: (v) => (v != _passCtrl.text) ? 'Şifreler eşleşmiyor' : null, ), if (_error != null) ...[ const SizedBox(height: 12), Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), decoration: BoxDecoration( color: AppColors.cancelledBg, borderRadius: BorderRadius.circular(10), border: Border.all( color: AppColors.cancelled.withValues(alpha: 0.3)), ), child: Row( children: [ const Icon(Icons.error_outline_rounded, color: AppColors.cancelled, size: 16), const SizedBox(width: 8), Expanded( child: Text( _error!, style: const TextStyle( color: AppColors.cancelled, fontSize: 13), ), ), ], ), ), ], const SizedBox(height: 20), FilledButton( onPressed: _loading ? null : _submit, style: FilledButton.styleFrom( backgroundColor: AppColors.primary, minimumSize: const Size.fromHeight(52), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), ), child: _loading ? const SizedBox( width: 22, height: 22, child: CircularProgressIndicator( strokeWidth: 2.5, color: Colors.white), ) : const Text( 'Kayıt Ol', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600), ), ), ], ), ).animate(delay: 100.ms).fadeIn(duration: 400.ms).slideY(begin: 0.1, end: 0), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( 'Zaten hesabın var mı?', style: TextStyle(color: AppColors.textSecondary, fontSize: 14), ), TextButton( onPressed: () => context.go(routeSignIn), style: TextButton.styleFrom( foregroundColor: AppColors.accent, padding: const EdgeInsets.symmetric(horizontal: 8), ), child: const Text( 'Giriş Yap', style: TextStyle(fontWeight: FontWeight.w600, fontSize: 14), ), ), ], ).animate(delay: 200.ms).fadeIn(duration: 400.ms), SizedBox(height: isMobile ? 32 : 16), ], ), ); } } // ── Feature bullet (desktop left panel) ────────────────────────────────────── class _FeatureBullet extends StatelessWidget { const _FeatureBullet({required this.icon, required this.text}); final IconData icon; final String text; @override Widget build(BuildContext context) { return Row( children: [ Container( width: 36, height: 36, decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(10), ), child: Icon(icon, size: 18, color: Colors.white), ), const SizedBox(width: 14), Text( text, style: TextStyle( fontSize: 15, color: Colors.white.withValues(alpha: 0.9), fontWeight: FontWeight.w500, ), ), ], ); } } // ── Form field ──────────────────────────────────────────────────────────────── class _Field extends StatelessWidget { const _Field({ required this.controller, required this.label, required this.icon, this.keyboardType, this.textCapitalization = TextCapitalization.none, this.textInputAction, this.obscureText = false, this.suffixIcon, this.onFieldSubmitted, this.validator, }); final TextEditingController controller; final String label; final IconData icon; final TextInputType? keyboardType; final TextCapitalization textCapitalization; final TextInputAction? textInputAction; final bool obscureText; final Widget? suffixIcon; final ValueChanged? onFieldSubmitted; final FormFieldValidator? validator; @override Widget build(BuildContext context) { return TextFormField( controller: controller, keyboardType: keyboardType, textCapitalization: textCapitalization, textInputAction: textInputAction, obscureText: obscureText, onFieldSubmitted: onFieldSubmitted, validator: validator, style: const TextStyle(fontSize: 15, color: AppColors.textPrimary), decoration: InputDecoration( labelText: label, prefixIcon: Icon(icon, size: 20, color: AppColors.textSecondary), suffixIcon: suffixIcon, filled: true, fillColor: AppColors.background, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: AppColors.border), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: AppColors.border), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: AppColors.accent, width: 2), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: AppColors.cancelled, width: 1.5), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: AppColors.cancelled, width: 2), ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), labelStyle: const TextStyle(color: AppColors.textSecondary, fontSize: 14), ), ); } }