MIF_E31221388/salonbooking/lib/page/register_page.dart

271 lines
8.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class RegisterPage extends StatefulWidget {
@override
_RegisterPageState createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
final _formKey = GlobalKey<FormState>();
final _name = TextEditingController();
final _email = TextEditingController();
final _password = TextEditingController();
final _confirmPassword = TextEditingController();
String _role = 'pelanggan';
bool _obscurePassword = true;
bool _obscureConfirmPassword = true;
Future<void> register() async {
if (!_formKey.currentState!.validate()) return;
try {
final response = await http.post(
Uri.parse('http://angeliasalon.my.id/api/register'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: jsonEncode({
'name': _name.text.trim(),
'email': _email.text.trim(),
'password': _password.text,
'password_confirmation': _confirmPassword.text,
'role': _role,
}),
);
if (response.statusCode == 201) {
final loginResponse = await http.post(
Uri.parse('http://angeliasalon.my.id/api/login'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: jsonEncode({
'email': _email.text.trim(),
'password': _password.text,
}),
);
if (loginResponse.statusCode == 200) {
final data = jsonDecode(loginResponse.body);
final token = data['access_token'];
final verifyResponse = await http.post(
Uri.parse('http://angeliasalon.my.id/api/email/verification-notification'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
},
);
if (verifyResponse.statusCode == 200) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Verifikasi Email'),
content: Text(
'Registrasi berhasil!\nKami telah mengirimkan email verifikasi ke ${_email.text.trim()}.\nSilakan cek email dan klik link verifikasi.',
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context); // Tutup dialog
Navigator.pop(context); // Kembali ke login
},
child: Text('OK'),
),
],
),
);
} else {
throw Exception('Gagal mengirim link verifikasi email.');
}
} else {
final err = jsonDecode(loginResponse.body);
throw Exception(err['message'] ?? 'Login gagal setelah registrasi');
}
} else {
final body = jsonDecode(response.body);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(body['message'] ?? 'Registrasi gagal'),
backgroundColor: Colors.red,
),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Terjadi kesalahan: ${e.toString()}'),
backgroundColor: Colors.red,
),
);
}
}
@override
Widget build(BuildContext context) {
final primaryColor = const Color(0xFFF06292);
final backgroundColor = const Color(0xFFFFF6F9);
final inputFillColor = const Color(0xFFFADADD);
return Scaffold(
backgroundColor: backgroundColor,
appBar: AppBar(
title: const Text('Register'),
backgroundColor: const Color(0xFFF48FB1),
),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 24),
child: Form(
key: _formKey,
child: Column(
children: [
Text(
'Create Your Account',
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: primaryColor,
),
),
const SizedBox(height: 24),
// Name
TextFormField(
controller: _name,
decoration: _inputDecoration('Name', Icons.person, inputFillColor),
validator: (value) => (value == null || value.isEmpty) ? 'Nama wajib diisi' : null,
),
const SizedBox(height: 16),
// Email
TextFormField(
controller: _email,
decoration: _inputDecoration('Email', Icons.email, inputFillColor),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) return 'Email wajib diisi';
final emailRegex = RegExp(r'^[^@]+@[^@]+\.[^@]+');
if (!emailRegex.hasMatch(value)) return 'Format email tidak valid';
return null;
},
),
const SizedBox(height: 16),
// Password
TextFormField(
controller: _password,
obscureText: _obscurePassword,
decoration: _inputDecorationWithToggle(
'Password',
Icons.lock,
inputFillColor,
_obscurePassword,
() => setState(() => _obscurePassword = !_obscurePassword),
),
validator: (value) => (value == null || value.length < 6) ? 'Minimal 6 karakter' : null,
),
const SizedBox(height: 16),
// Confirm Password
TextFormField(
controller: _confirmPassword,
obscureText: _obscureConfirmPassword,
decoration: _inputDecorationWithToggle(
'Confirm Password',
Icons.lock_outline,
inputFillColor,
_obscureConfirmPassword,
() => setState(() => _obscureConfirmPassword = !_obscureConfirmPassword),
),
validator: (value) => (value != _password.text) ? 'Password tidak sama' : null,
),
const SizedBox(height: 20),
// Role Dropdown
DropdownButtonFormField<String>(
value: _role,
items: ['pelanggan', 'karyawan'].map((role) {
return DropdownMenuItem(
value: role,
child: Text(role[0].toUpperCase() + role.substring(1)),
);
}).toList(),
onChanged: (val) => setState(() => _role = val!),
decoration: _inputDecoration('Role', Icons.group, inputFillColor),
),
const SizedBox(height: 32),
// Register Button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: register,
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
textStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
elevation: 5,
),
child: const Text('Register'),
),
),
],
),
),
),
);
}
InputDecoration _inputDecoration(String label, IconData icon, Color fillColor) {
return InputDecoration(
labelText: label,
filled: true,
fillColor: fillColor,
prefixIcon: Icon(icon, color: Colors.pinkAccent),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide.none,
),
);
}
InputDecoration _inputDecorationWithToggle(
String label,
IconData icon,
Color fillColor,
bool isObscured,
VoidCallback toggle,
) {
return InputDecoration(
labelText: label,
filled: true,
fillColor: fillColor,
prefixIcon: Icon(icon, color: Colors.pinkAccent),
suffixIcon: IconButton(
icon: Icon(
isObscured ? Icons.visibility_off : Icons.visibility,
color: Colors.pinkAccent,
),
onPressed: toggle,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide.none,
),
);
}
}