E32221324_Iot_Running/lib/screens/auth/register_screen.dart

252 lines
9.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:ta_running/screens/auth/login_screen.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class RegisterScreen extends StatefulWidget {
const RegisterScreen({super.key});
@override
State<RegisterScreen> createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
final _formKey = GlobalKey<FormState>();
final _usernameController = TextEditingController();
String? _selectedGender;
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
bool _obscurePassword = true;
Future<void> _register() async {
if (_formKey.currentState!.validate()) {
try {
final userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text.trim(),
password: _passwordController.text.trim(),
);
// Simpan data tambahan ke Firestore
await FirebaseFirestore.instance.collection('users').doc(userCredential.user!.uid).set({
'username': _usernameController.text.trim(),
'gender': _selectedGender,
'email': _emailController.text.trim(),
'role': 'runner',
});
// Arahkan ke login setelah berhasil
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => const LoginScreen()),
(route) => false,
);
} on FirebaseAuthException catch (e) {
String message = '';
if (e.code == 'email-already-in-use') {
message = 'Email sudah digunakan.';
} else {
message = 'Registrasi gagal: ${e.message}';
}
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Registrasi gagal: ${e.toString()}")));
}
}
}
@override
Widget build(BuildContext context) {
final inputBorder = OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.blueAccent),
);
return Scaffold(
backgroundColor: Colors.white,
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: Container(
decoration: const BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20),
),
),
padding: const EdgeInsets.only(top: 40), // untuk push tulisan agak ke bawah
child: const Center(
child: Text(
"Register",
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.bold,
),
),
),
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: Form(
key: _formKey,
child: Column(
children: [
// Logo di atas
Image.asset(
'images/run.png',
width: 95,
height: 95,
fit: BoxFit.contain,
),
const SizedBox(height: 19),
// Judul
Text(
'Daftar Akun',
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 32),
// Username
TextFormField(
controller: _usernameController,
decoration: InputDecoration(
labelText: "Username",
border: inputBorder,
focusedBorder: inputBorder.copyWith(borderSide: const BorderSide(color: Colors.blueAccent, width: 2)),
prefixIcon: const Icon(Icons.person, color: Colors.blueAccent),
),
validator: (value) => value == null || value.isEmpty ? "Masukkan username" : null,
),
const SizedBox(height: 20),
// Gender Dropdown
DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: "Gender",
border: inputBorder,
focusedBorder: inputBorder.copyWith(borderSide: const BorderSide(color: Colors.blueAccent, width: 2)),
prefixIcon: const Icon(Icons.wc, color: Colors.blueAccent),
),
value: _selectedGender,
items: const [
DropdownMenuItem(value: 'Laki-laki', child: Text('Laki-laki')),
DropdownMenuItem(value: 'Perempuan', child: Text('Perempuan')),
],
onChanged: (value) => setState(() => _selectedGender = value),
validator: (value) => value == null ? "Pilih gender" : null,
),
const SizedBox(height: 20),
// Email
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: "Email",
border: inputBorder,
focusedBorder: inputBorder.copyWith(borderSide: const BorderSide(color: Colors.blueAccent, width: 2)),
prefixIcon: const Icon(Icons.email, color: Colors.blueAccent),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) return "Masukkan email";
final emailRegex = RegExp(r"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
if (!emailRegex.hasMatch(value)) return "Format email tidak valid";
return null;
},
),
const SizedBox(height: 20),
// Password
TextFormField(
controller: _passwordController,
obscureText: _obscurePassword,
decoration: InputDecoration(
labelText: "Password",
border: inputBorder,
focusedBorder: inputBorder.copyWith(borderSide: const BorderSide(color: Colors.blueAccent, width: 2)),
prefixIcon: const Icon(Icons.lock, color: Colors.blueAccent),
suffixIcon: IconButton(
icon: Icon(_obscurePassword ? Icons.visibility : Icons.visibility_off, color: Colors.blueAccent),
onPressed: () => setState(() => _obscurePassword = !_obscurePassword),
),
),
validator: (value) {
if (value == null || value.isEmpty) return "Masukkan password";
if (!RegExp(r'^(?=.*[a-zA-Z])(?=.*\d).{6,}$').hasMatch(value)) {
return "Password harus kombinasi huruf & angka";
}
return null;
},
),
const SizedBox(height: 36),
// Register Button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _register,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 14),
backgroundColor: Colors.blueAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 5,
),
child: const Text(
"Daftar",
style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.bold),
),
),
),
const SizedBox(height: 12),
// Link Login
TextButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const LoginScreen()),
),
child: RichText(
text: TextSpan(
children: [
const TextSpan(
text: 'Sudah punya akun? ',
style: TextStyle(
fontSize: 16,
color: Colors.black,
fontWeight: FontWeight.w400,
),
),
TextSpan(
text: 'Login',
style: const TextStyle(
fontSize: 16,
color: Colors.blueAccent,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
],
),
),
),
);
}
}