Files
bumrent_app/lib/app/modules/auth/views/registration_view.dart
Andreas Malvino e7090af3da first commit
2025-06-02 22:39:03 +07:00

550 lines
17 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(
'Pendaftaran hanya dapat dilakukan oleh warga dan mitra yang sudah terverivikasi. Silahkan hubungi petugas atau kunjungi kantor untuk informasi lebih lanjut.',
style: TextStyle(
fontSize: 13,
color: AppColors.textPrimary,
height: 1.4,
),
),
],
),
),
],
),
);
}
Widget _buildRegistrationForm() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Email Input
_buildInputLabel('Email'),
const SizedBox(height: 8),
_buildEmailField(),
const SizedBox(height: 20),
// Password Input
_buildInputLabel('Password'),
const SizedBox(height: 8),
_buildPasswordField(),
const SizedBox(height: 20),
// NIK Input
_buildInputLabel('NIK'),
const SizedBox(height: 8),
_buildNikField(),
const SizedBox(height: 20),
// Phone Number Input
_buildInputLabel('No. Hp'),
const SizedBox(height: 8),
_buildPhoneField(),
const SizedBox(height: 20),
// Role Selection Dropdown
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Daftar Sebagai',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
const SizedBox(height: 8),
Container(
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey[300]!, width: 1),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Obx(
() => DropdownButtonHideUnderline(
child: DropdownButton<String>(
isExpanded: true,
value: controller.selectedRole.value,
hint: const Text('Pilih Peran'),
items: [
DropdownMenuItem(
value: 'WARGA',
child: const Text('Warga'),
),
DropdownMenuItem(
value: 'PETUGAS_MITRA',
child: const Text('Mitra'),
),
],
onChanged: (value) {
controller.setRole(value);
},
icon: const Icon(Icons.arrow_drop_down),
style: const TextStyle(
color: Colors.black87,
fontSize: 14,
),
),
),
),
),
),
],
),
const SizedBox(height: 20),
// Error message
Obx(
() =>
controller.errorMessage.value.isNotEmpty
? Container(
margin: const EdgeInsets.only(top: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColors.errorLight,
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
Icon(
Icons.error_outline,
color: AppColors.error,
size: 20,
),
const SizedBox(width: 8),
Expanded(
child: Text(
controller.errorMessage.value,
style: TextStyle(
color: AppColors.error,
fontSize: 13,
),
),
),
],
),
)
: const SizedBox.shrink(),
),
],
);
}
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 _buildNikField() {
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.nik.value = value,
keyboardType: TextInputType.number,
style: TextStyle(fontSize: 16, color: AppColors.textPrimary),
decoration: InputDecoration(
hintText: 'Masukkan NIK anda',
hintStyle: TextStyle(color: AppColors.textLight),
prefixIcon: Icon(
Icons.credit_card_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 _buildPhoneField() {
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.phoneNumber.value = value,
keyboardType: TextInputType.phone,
style: TextStyle(fontSize: 16, color: AppColors.textPrimary),
decoration: InputDecoration(
hintText: 'Masukkan nomor HP anda',
hintStyle: TextStyle(color: AppColors.textLight),
prefixIcon: Icon(Icons.phone_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 _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,
),
),
),
],
);
}
}