299 lines
10 KiB
Dart
299 lines
10 KiB
Dart
import 'package:firebase_auth/firebase_auth.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
|
|
import 'toast.dart';
|
|
import 'login_screen.dart';
|
|
|
|
class SignUpScreen extends StatefulWidget {
|
|
const SignUpScreen({super.key});
|
|
|
|
@override
|
|
State<SignUpScreen> createState() => _SignUpScreenState();
|
|
}
|
|
|
|
class _SignUpScreenState extends State<SignUpScreen> {
|
|
final TextEditingController _usernameController = TextEditingController();
|
|
final TextEditingController _emailController = TextEditingController();
|
|
final TextEditingController _passwordController = TextEditingController();
|
|
final TextEditingController _confirmPasswordController =
|
|
TextEditingController();
|
|
|
|
bool _obscurePassword = true;
|
|
bool _obscureConfirm = true;
|
|
bool _isSigningUp = false;
|
|
|
|
@override
|
|
void dispose() {
|
|
_usernameController.dispose();
|
|
_emailController.dispose();
|
|
_passwordController.dispose();
|
|
_confirmPasswordController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> _signUp() async {
|
|
String username = _usernameController.text.trim();
|
|
String email = _emailController.text.trim();
|
|
String password = _passwordController.text;
|
|
String confirmPassword = _confirmPasswordController.text;
|
|
|
|
if (username.isEmpty || email.isEmpty || password.isEmpty) {
|
|
showToast(message: "Semua field wajib diisi.");
|
|
return;
|
|
}
|
|
|
|
if (password != confirmPassword) {
|
|
showToast(message: "Konfirmasi password tidak cocok.");
|
|
return;
|
|
}
|
|
|
|
setState(() {
|
|
_isSigningUp = true;
|
|
});
|
|
|
|
try {
|
|
// 1. Buat akun dengan Firebase Auth
|
|
UserCredential userCredential = await FirebaseAuth.instance
|
|
.createUserWithEmailAndPassword(email: email, password: password);
|
|
|
|
// 2. Ambil UID pengguna
|
|
String uid = userCredential.user!.uid;
|
|
|
|
// 3. Simpan data user ke Firestore
|
|
await FirebaseFirestore.instance.collection('users').doc(uid).set({
|
|
'email': email,
|
|
'username': username,
|
|
'createdAt': Timestamp.now(),
|
|
});
|
|
|
|
showToast(message: "Akun berhasil dibuat!");
|
|
|
|
// 4. Navigasi ke Login Screen
|
|
if (mounted) {
|
|
Navigator.pushReplacement(
|
|
context,
|
|
MaterialPageRoute(builder: (context) => const LoginScreen()),
|
|
);
|
|
}
|
|
} on FirebaseAuthException catch (e) {
|
|
switch (e.code) {
|
|
case 'email-already-in-use':
|
|
showToast(message: "Email sudah digunakan.");
|
|
break;
|
|
case 'invalid-email':
|
|
showToast(message: "Format email tidak valid.");
|
|
break;
|
|
case 'weak-password':
|
|
showToast(message: "Password terlalu lemah (minimal 6 karakter).");
|
|
break;
|
|
default:
|
|
showToast(message: "Error: ${e.message}");
|
|
}
|
|
} catch (e) {
|
|
showToast(message: "Terjadi kesalahan saat mendaftar.");
|
|
} finally {
|
|
if (mounted) {
|
|
setState(() {
|
|
_isSigningUp = false;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: Colors.white,
|
|
body: Column(
|
|
children: [
|
|
// Header
|
|
Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.only(top: 80, bottom: 30),
|
|
decoration: const BoxDecoration(
|
|
color: Color(0xFF3FA535),
|
|
borderRadius: BorderRadius.only(
|
|
bottomLeft: Radius.circular(40),
|
|
bottomRight: Radius.circular(40),
|
|
),
|
|
),
|
|
child: Column(
|
|
children: [
|
|
Image.asset(
|
|
'assets/images/logoputih.png',
|
|
width: 50,
|
|
height: 50,
|
|
),
|
|
const SizedBox(height: 10),
|
|
const Text(
|
|
'Sign Up to Your Account',
|
|
style: TextStyle(
|
|
fontSize: 22,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
const SizedBox(height: 5),
|
|
const Text(
|
|
'Enter your email and password to sign up',
|
|
style: TextStyle(fontSize: 14, color: Colors.white70),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
// Form
|
|
Expanded(
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.all(24),
|
|
child: Container(
|
|
padding: const EdgeInsets.all(24),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(24),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.grey.shade300,
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 5),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
const Text(
|
|
'Sign Up',
|
|
style: TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
// Username
|
|
TextField(
|
|
controller: _usernameController,
|
|
decoration: const InputDecoration(
|
|
prefixIcon: Icon(Icons.person_outline),
|
|
labelText: 'Username',
|
|
border: UnderlineInputBorder(),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// Email
|
|
TextField(
|
|
controller: _emailController,
|
|
decoration: const InputDecoration(
|
|
prefixIcon: Icon(Icons.email_outlined),
|
|
labelText: 'Email',
|
|
border: UnderlineInputBorder(),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// Password
|
|
TextField(
|
|
controller: _passwordController,
|
|
obscureText: _obscurePassword,
|
|
decoration: InputDecoration(
|
|
prefixIcon: const Icon(Icons.lock_outline),
|
|
labelText: 'Password',
|
|
border: const UnderlineInputBorder(),
|
|
suffixIcon: IconButton(
|
|
icon: Icon(
|
|
_obscurePassword
|
|
? Icons.visibility_off
|
|
: Icons.visibility,
|
|
),
|
|
onPressed: () {
|
|
setState(() {
|
|
_obscurePassword = !_obscurePassword;
|
|
});
|
|
},
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// Confirm Password
|
|
TextField(
|
|
controller: _confirmPasswordController,
|
|
obscureText: _obscureConfirm,
|
|
decoration: InputDecoration(
|
|
prefixIcon: const Icon(Icons.lock_outline),
|
|
labelText: 'Confirm Password',
|
|
border: const UnderlineInputBorder(),
|
|
suffixIcon: IconButton(
|
|
icon: Icon(
|
|
_obscureConfirm
|
|
? Icons.visibility_off
|
|
: Icons.visibility,
|
|
),
|
|
onPressed: () {
|
|
setState(() {
|
|
_obscureConfirm = !_obscureConfirm;
|
|
});
|
|
},
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 30),
|
|
|
|
// Button
|
|
ElevatedButton(
|
|
onPressed: _signUp,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: const Color(0xFF3FA535),
|
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(30),
|
|
),
|
|
),
|
|
child:
|
|
_isSigningUp
|
|
? const CircularProgressIndicator(
|
|
color: Colors.white,
|
|
)
|
|
: const Text(
|
|
'Sign Up',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
// Redirect ke Login
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
const Text("Already have an account? "),
|
|
GestureDetector(
|
|
onTap: () {
|
|
Navigator.pop(context);
|
|
},
|
|
child: const Text(
|
|
'Sign In',
|
|
style: TextStyle(
|
|
color: Color(0xFF3FA535),
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|