import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class ResetPasswordScreen extends StatefulWidget { const ResetPasswordScreen({super.key}); @override State createState() => _ResetPasswordScreenState(); } class _ResetPasswordScreenState extends State { final TextEditingController nameController = TextEditingController(); final TextEditingController emailController = TextEditingController(); final TextEditingController passwordController = TextEditingController(); bool showNewPassword = false; bool _isLoading = false; bool _hidePassword = true; String apiUrl = "http://192.168.100.9/kopikaocare_api/reset_password.php"; Future resetPassword() async { if (passwordController.text.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Password baru tidak boleh kosong'), backgroundColor: Colors.orange, ), ); return; } setState(() => _isLoading = true); var response = await http.post( Uri.parse(apiUrl), body: { "name": nameController.text, "email": emailController.text, "password": passwordController.text, }, ); var data = jsonDecode(response.body); setState(() => _isLoading = false); if (data['status'] == "success") { showDialog( context: context, barrierDismissible: false, builder: (context) { return AlertDialog( backgroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), title: const Row( children: [ Icon(Icons.check_circle, color: Colors.green, size: 28), SizedBox(width: 10), Text( 'Berhasil!', style: TextStyle(color: Colors.green), ), ], ), content: const Text('Password berhasil diubah'), actions: [ TextButton( onPressed: () { Navigator.pop(context); // close dialog Navigator.pop(context); // balik ke login }, child: const Text('OK'), ), ], ); }, ); } else { showDialog( context: context, builder: (context) { return AlertDialog( backgroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), title: const Row( children: [ Icon(Icons.error, color: Colors.red, size: 28), SizedBox(width: 10), Text( 'Gagal!', style: TextStyle(color: Colors.red), ), ], ), content: const Text('Nama atau email tidak cocok'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('OK'), ), ], ); }, ); } } void verifyUser() { if (nameController.text.isEmpty || emailController.text.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Nama dan email harus diisi'), backgroundColor: Colors.orange, ), ); return; } setState(() { showNewPassword = true; }); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xfff8f9fa), appBar: AppBar( title: const Text( 'Reset Password', style: TextStyle(fontWeight: FontWeight.bold), ), backgroundColor: Colors.transparent, foregroundColor: Colors.red, elevation: 0, ), body: SafeArea( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(24), child: Column( children: [ // Header Icon Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: [Colors.red.shade100, Colors.red.shade50], ), ), child: Icon( showNewPassword ? Icons.lock_reset : Icons.lock_outline, size: 60, color: Colors.red, ), ), const SizedBox(height: 20), Text( showNewPassword ? 'Create New Password' : 'Verify Your Identity', style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xff2d2d2d), ), ), const SizedBox(height: 8), Text( showNewPassword ? 'Enter your new password below' : 'Enter your name and email to reset password', style: TextStyle( fontSize: 14, color: Colors.grey.shade600, ), textAlign: TextAlign.center, ), const SizedBox(height: 40), // Form Container Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(25), boxShadow: [ BoxShadow( blurRadius: 15, color: Colors.black.withOpacity(0.05), offset: const Offset(0, 5), ), ], ), child: Column( children: [ // Step 1: Verify Identity if (!showNewPassword) ...[ // Name Field TextField( controller: nameController, style: const TextStyle(fontSize: 16), decoration: InputDecoration( hintText: 'Full Name', prefixIcon: const Icon(Icons.person_outline, color: Colors.red), border: OutlineInputBorder( borderRadius: BorderRadius.circular(20), borderSide: BorderSide.none, ), filled: true, fillColor: Colors.white, contentPadding: const EdgeInsets.symmetric(vertical: 18), ), ), Divider( height: 1, color: Colors.grey.shade200, ), // Email Field TextField( controller: emailController, style: const TextStyle(fontSize: 16), keyboardType: TextInputType.emailAddress, decoration: InputDecoration( hintText: 'Email Address', prefixIcon: const Icon(Icons.email_outlined, color: Colors.red), border: OutlineInputBorder( borderRadius: BorderRadius.circular(20), borderSide: BorderSide.none, ), filled: true, fillColor: Colors.white, contentPadding: const EdgeInsets.symmetric(vertical: 18), ), ), ], // Step 2: New Password if (showNewPassword) ...[ // New Password Field TextField( controller: passwordController, obscureText: _hidePassword, style: const TextStyle(fontSize: 16), decoration: InputDecoration( hintText: 'New Password', prefixIcon: const Icon(Icons.lock_outline, color: Colors.red), suffixIcon: IconButton( icon: Icon( _hidePassword ? Icons.visibility_off : Icons.visibility, color: Colors.grey, ), onPressed: () { setState(() { _hidePassword = !_hidePassword; }); }, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(20), borderSide: BorderSide.none, ), filled: true, fillColor: Colors.white, contentPadding: const EdgeInsets.symmetric(vertical: 18), ), ), // Password Strength Indicator if (passwordController.text.isNotEmpty) ...[ const SizedBox(height: 10), Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: _buildPasswordStrength(passwordController.text), ), ], ], ], ), ), const SizedBox(height: 30), // Action Button SizedBox( width: double.infinity, height: 55, child: ElevatedButton( onPressed: _isLoading ? null : (showNewPassword ? resetPassword : verifyUser), style: ElevatedButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), ), child: _isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white, ), ) : Text( showNewPassword ? 'Save Password' : 'Verify', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, letterSpacing: 1, ), ), ), ), // Back Button (only on step 2) if (showNewPassword) ...[ const SizedBox(height: 15), TextButton( onPressed: () { setState(() { showNewPassword = false; passwordController.clear(); }); }, child: const Text( 'Back', style: TextStyle(color: Colors.grey), ), ), ], const SizedBox(height: 20), ], ), ), ), ), ); } Widget _buildPasswordStrength(String password) { int strength = _calculatePasswordStrength(password); String strengthText = ''; Color strengthColor = Colors.red; if (strength <= 2) { strengthText = 'Weak'; strengthColor = Colors.red; } else if (strength <= 4) { strengthText = 'Medium'; strengthColor = Colors.orange; } else { strengthText = 'Strong'; strengthColor = Colors.green; } return Row( children: [ Expanded( child: LinearProgressIndicator( value: strength / 6, backgroundColor: Colors.grey.shade200, valueColor: AlwaysStoppedAnimation(strengthColor), minHeight: 4, borderRadius: BorderRadius.circular(2), ), ), const SizedBox(width: 10), Text( strengthText, style: TextStyle( fontSize: 12, color: strengthColor, fontWeight: FontWeight.w500, ), ), ], ); } int _calculatePasswordStrength(String password) { int strength = 0; if (password.length >= 6) strength++; if (password.length >= 10) strength++; if (password.contains(RegExp(r'[A-Z]'))) strength++; if (password.contains(RegExp(r'[a-z]'))) strength++; if (password.contains(RegExp(r'[0-9]'))) strength++; if (password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'))) strength++; return strength; } }