484 lines
14 KiB
Dart
484 lines
14 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import '../controllers/auth_controller.dart';
|
|
import '../../../theme/app_colors.dart';
|
|
|
|
class RegistrationView extends GetView<AuthController> {
|
|
const RegistrationView({Key? key}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: AppColors.background,
|
|
body: SafeArea(
|
|
child: Stack(
|
|
children: [
|
|
// Background gradient
|
|
Positioned(
|
|
top: -100,
|
|
right: -100,
|
|
child: Container(
|
|
width: 300,
|
|
height: 300,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
gradient: RadialGradient(
|
|
colors: [
|
|
AppColors.primaryLight.withOpacity(0.2),
|
|
AppColors.background.withOpacity(0),
|
|
],
|
|
stops: const [0.0, 1.0],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Positioned(
|
|
bottom: -80,
|
|
left: -80,
|
|
child: Container(
|
|
width: 200,
|
|
height: 200,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
gradient: RadialGradient(
|
|
colors: [
|
|
AppColors.accent.withOpacity(0.15),
|
|
AppColors.background.withOpacity(0),
|
|
],
|
|
stops: const [0.0, 1.0],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
// Content
|
|
SingleChildScrollView(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(24.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
_buildBackButton(),
|
|
const SizedBox(height: 20),
|
|
_buildHeader(),
|
|
const SizedBox(height: 24),
|
|
_buildRegistrationForm(),
|
|
const SizedBox(height: 32),
|
|
_buildRegisterButton(),
|
|
const SizedBox(height: 24),
|
|
_buildImportantInfo(),
|
|
const SizedBox(height: 24),
|
|
_buildLoginLink(),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildBackButton() {
|
|
return Align(
|
|
alignment: Alignment.topLeft,
|
|
child: InkWell(
|
|
onTap: () => Get.back(),
|
|
borderRadius: BorderRadius.circular(50),
|
|
child: Container(
|
|
padding: const EdgeInsets.all(10),
|
|
decoration: BoxDecoration(
|
|
color: AppColors.surface,
|
|
shape: BoxShape.circle,
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: AppColors.shadow,
|
|
blurRadius: 8,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: const Icon(
|
|
Icons.arrow_back,
|
|
size: 20,
|
|
color: AppColors.primary,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildHeader() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Hero(
|
|
tag: 'logo',
|
|
child: Container(
|
|
width: 80,
|
|
height: 80,
|
|
decoration: BoxDecoration(
|
|
color: AppColors.primarySoft,
|
|
borderRadius: BorderRadius.circular(20),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: AppColors.primary.withOpacity(0.2),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 4),
|
|
),
|
|
],
|
|
),
|
|
child: Icon(
|
|
Icons.apartment_rounded,
|
|
size: 40,
|
|
color: AppColors.primary,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 24),
|
|
Text(
|
|
'Daftar Akun',
|
|
style: TextStyle(
|
|
fontSize: 28,
|
|
fontWeight: FontWeight.bold,
|
|
color: AppColors.textPrimary,
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
Text(
|
|
'Lengkapi data berikut untuk mendaftar',
|
|
style: TextStyle(fontSize: 16, color: AppColors.textSecondary),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildImportantInfo() {
|
|
return Container(
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: AppColors.warningLight,
|
|
borderRadius: BorderRadius.circular(16),
|
|
border: Border.all(color: AppColors.warning.withOpacity(0.3)),
|
|
),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: AppColors.warning.withOpacity(0.2),
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(Icons.info_outline, size: 20, color: AppColors.warning),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'Informasi Penting',
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.bold,
|
|
color: AppColors.warning,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'Setelah pendaftaran lengkapi data diri untuk dapat melakukan sewa',
|
|
style: TextStyle(
|
|
fontSize: 13,
|
|
color: AppColors.textPrimary,
|
|
height: 1.4,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildRegistrationForm() {
|
|
return Form(
|
|
key: controller.formKey,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
_buildInputLabel('Email'),
|
|
_buildEmailField(),
|
|
const SizedBox(height: 16),
|
|
_buildInputLabel('Password'),
|
|
_buildPasswordField(),
|
|
const SizedBox(height: 16),
|
|
_buildInputLabel('Konfirmasi Password'),
|
|
_buildConfirmPasswordField(),
|
|
const SizedBox(height: 16),
|
|
_buildInputLabel('Nama Lengkap'),
|
|
_buildNameField(),
|
|
const SizedBox(height: 16),
|
|
_buildInputLabel('No HP'),
|
|
_buildPhoneField(),
|
|
const SizedBox(height: 16),
|
|
_buildInputLabel('Alamat Lengkap'),
|
|
_buildAlamatField(),
|
|
const SizedBox(height: 16),
|
|
// Removed: NIK, No HP, and Dropdown Daftar Sebagai
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildInputLabel(String label) {
|
|
return Text(
|
|
label,
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
color: AppColors.textPrimary,
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildEmailField() {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: AppColors.surface,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: AppColors.shadow,
|
|
blurRadius: 8,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: TextField(
|
|
onChanged: (value) => controller.email.value = value,
|
|
keyboardType: TextInputType.emailAddress,
|
|
style: TextStyle(fontSize: 16, color: AppColors.textPrimary),
|
|
decoration: InputDecoration(
|
|
hintText: 'Masukkan email anda',
|
|
hintStyle: TextStyle(color: AppColors.textLight),
|
|
prefixIcon: Icon(Icons.email_outlined, color: AppColors.primary),
|
|
border: InputBorder.none,
|
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
borderSide: BorderSide.none,
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
borderSide: BorderSide(color: AppColors.primary, width: 1.5),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildPasswordField() {
|
|
return Obx(
|
|
() => Container(
|
|
decoration: BoxDecoration(
|
|
color: AppColors.surface,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: AppColors.shadow,
|
|
blurRadius: 8,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: TextField(
|
|
onChanged: (value) => controller.password.value = value,
|
|
obscureText: !controller.isPasswordVisible.value,
|
|
style: TextStyle(fontSize: 16, color: AppColors.textPrimary),
|
|
decoration: InputDecoration(
|
|
hintText: 'Masukkan password anda',
|
|
hintStyle: TextStyle(color: AppColors.textLight),
|
|
prefixIcon: Icon(Icons.lock_outlined, color: AppColors.primary),
|
|
suffixIcon: IconButton(
|
|
icon: Icon(
|
|
controller.isPasswordVisible.value
|
|
? Icons.visibility
|
|
: Icons.visibility_off,
|
|
color: AppColors.iconGrey,
|
|
),
|
|
onPressed: controller.togglePasswordVisibility,
|
|
),
|
|
border: InputBorder.none,
|
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
borderSide: BorderSide.none,
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
borderSide: BorderSide(color: AppColors.primary, width: 1.5),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildConfirmPasswordField() {
|
|
return Obx(
|
|
() => TextFormField(
|
|
controller: controller.confirmPasswordController,
|
|
obscureText: !controller.isConfirmPasswordVisible.value,
|
|
decoration: InputDecoration(
|
|
hintText: 'Masukkan ulang password anda',
|
|
suffixIcon: IconButton(
|
|
icon: Icon(
|
|
controller.isConfirmPasswordVisible.value
|
|
? Icons.visibility
|
|
: Icons.visibility_off,
|
|
),
|
|
onPressed: controller.toggleConfirmPasswordVisibility,
|
|
),
|
|
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 16,
|
|
vertical: 14,
|
|
),
|
|
),
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Konfirmasi password tidak boleh kosong';
|
|
}
|
|
if (value != controller.passwordController.text) {
|
|
return 'Password tidak cocok';
|
|
}
|
|
return null;
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildNameField() {
|
|
return TextFormField(
|
|
controller: controller.nameController,
|
|
decoration: InputDecoration(
|
|
hintText: 'Masukkan nama lengkap anda',
|
|
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 16,
|
|
vertical: 14,
|
|
),
|
|
),
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Nama lengkap tidak boleh kosong';
|
|
}
|
|
return null;
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildPhoneField() {
|
|
return TextFormField(
|
|
keyboardType: TextInputType.phone,
|
|
decoration: InputDecoration(
|
|
hintText: 'Masukkan nomor HP anda',
|
|
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 16,
|
|
vertical: 14,
|
|
),
|
|
),
|
|
onChanged: (value) => controller.phoneNumber.value = value,
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'No HP tidak boleh kosong';
|
|
}
|
|
if (!value.startsWith('08') || value.length < 10) {
|
|
return 'Nomor HP tidak valid (harus diawali 08 dan minimal 10 digit)';
|
|
}
|
|
return null;
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildAlamatField() {
|
|
return TextFormField(
|
|
decoration: InputDecoration(
|
|
hintText: 'Masukkan alamat lengkap anda',
|
|
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 16,
|
|
vertical: 14,
|
|
),
|
|
),
|
|
onChanged: (value) => controller.alamatLengkap.value = value,
|
|
validator: (value) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Alamat lengkap tidak boleh kosong';
|
|
}
|
|
return null;
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildRegisterButton() {
|
|
return Obx(
|
|
() => ElevatedButton(
|
|
onPressed: controller.isLoading.value ? null : controller.registerUser,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColors.primary,
|
|
foregroundColor: AppColors.buttonText,
|
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
elevation: 0,
|
|
disabledBackgroundColor: AppColors.primary.withOpacity(0.6),
|
|
),
|
|
child:
|
|
controller.isLoading.value
|
|
? const SizedBox(
|
|
height: 24,
|
|
width: 24,
|
|
child: CircularProgressIndicator(
|
|
color: Colors.white,
|
|
strokeWidth: 2,
|
|
),
|
|
)
|
|
: const Text(
|
|
'Daftar',
|
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildLoginLink() {
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
'Sudah punya akun? ',
|
|
style: TextStyle(color: AppColors.textSecondary, fontSize: 14),
|
|
),
|
|
GestureDetector(
|
|
onTap: () {
|
|
Get.back(); // Back to login page
|
|
},
|
|
child: Text(
|
|
'Masuk',
|
|
style: TextStyle(
|
|
color: AppColors.primary,
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 14,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|