418 lines
15 KiB
Dart
418 lines
15 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:niogu_app/core/constants/app_asset.dart';
|
|
import 'package:niogu_app/core/constants/app_color.dart';
|
|
import 'package:niogu_app/core/constants/app_font_size.dart';
|
|
import 'package:niogu_app/core/errors/exceptions.dart';
|
|
import 'package:niogu_app/core/providers/app_provider.dart';
|
|
import 'package:niogu_app/core/router/app_route.dart';
|
|
import 'package:niogu_app/core/utils/log_message.dart';
|
|
import 'package:niogu_app/core/system/system_setting.dart';
|
|
import 'package:niogu_app/core/widgets/custom_snackbar.dart';
|
|
import 'package:niogu_app/core/widgets/custom_text_form_field.dart';
|
|
import 'package:niogu_app/features/auth/domain/entities/user.dart';
|
|
import 'package:niogu_app/features/auth/presentation/providers/auth_provider.dart';
|
|
import 'package:sizer/sizer.dart';
|
|
|
|
class RegistrationScreen extends ConsumerStatefulWidget {
|
|
const RegistrationScreen({super.key});
|
|
|
|
@override
|
|
ConsumerState<RegistrationScreen> createState() => _RegistrationScreenState();
|
|
}
|
|
|
|
class _RegistrationScreenState extends ConsumerState<RegistrationScreen> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
|
|
final _businessNameController = TextEditingController();
|
|
|
|
final _nameController = TextEditingController();
|
|
|
|
final _phoneNumberController = TextEditingController();
|
|
|
|
final _emailController = TextEditingController();
|
|
|
|
final _passwordController = TextEditingController();
|
|
|
|
final _passwordConfirmController = TextEditingController();
|
|
|
|
bool _obscurePassword = true;
|
|
|
|
bool _obscurePasswordConfirm = true;
|
|
|
|
@override
|
|
void initState() {
|
|
// TODO: implement initState
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
// TODO: implement dispose
|
|
_businessNameController.dispose();
|
|
_nameController.dispose();
|
|
_phoneNumberController.dispose();
|
|
_emailController.dispose();
|
|
_passwordController.dispose();
|
|
_passwordConfirmController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
String? _validation({
|
|
String? value,
|
|
String? message,
|
|
bool isEmail = false,
|
|
bool isPassword = false,
|
|
bool isPasswordConfirm = false,
|
|
}) {
|
|
if (value == null || value.isEmpty) {
|
|
return message;
|
|
}
|
|
|
|
final _emailRegex = RegExp(
|
|
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
|
|
);
|
|
|
|
if (isEmail && !_emailRegex.hasMatch(value)) {
|
|
return "Email tidak valid";
|
|
}
|
|
|
|
if (isPassword) {
|
|
if (value.length < 8) {
|
|
return "Password minimal harus 8 karakter";
|
|
}
|
|
|
|
final passwordRegExp = RegExp(
|
|
r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&#])[A-Za-z\d@$!%*?&#]{8,}$',
|
|
);
|
|
|
|
if (!passwordRegExp.hasMatch(value)) {
|
|
return "Gunakan huruf besar, kecil, angka, dan simbol";
|
|
}
|
|
}
|
|
|
|
if (isPasswordConfirm && value != _passwordController.text.trim()) {
|
|
return "Konfirmasi password tidak sesuai";
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
Future<void> _setCurrentOutlet() async {
|
|
final currentOutletId = await SystemSetting.getCurrentOutletId();
|
|
|
|
final currentOutletName = await SystemSetting.getCurrentOutletName();
|
|
|
|
ref.read(currentOutletIdProvider.notifier).state = currentOutletId;
|
|
|
|
ref.read(currentOutletNameProvider.notifier).state = currentOutletName;
|
|
}
|
|
|
|
Future<void> _setCurrentUser() async {
|
|
final currentUserId = await SystemSetting.getCurrentUserId();
|
|
|
|
final currentUserName = await SystemSetting.getCurrentUserName();
|
|
|
|
final currentUserEmail = await SystemSetting.getCurrentUserEmail();
|
|
|
|
final currentUserRole = await SystemSetting.getCurrentUserRole();
|
|
|
|
final outletIdByOwner = await SystemSetting.getOutletIdByOwner();
|
|
|
|
ref.read(currentUserIdProvider.notifier).state = currentUserId;
|
|
|
|
ref.read(currentUserNameProvider.notifier).state = currentUserName;
|
|
|
|
ref.read(currentUserEmailProvider.notifier).state = currentUserEmail;
|
|
|
|
ref.read(currentUserRoleProvider.notifier).state = currentUserRole;
|
|
|
|
ref.read(outletIdByOwnerProvider.notifier).state = outletIdByOwner;
|
|
|
|
ref.read(currentStatusLoginProvider.notifier).state = true;
|
|
}
|
|
|
|
Future<void> _register() async {
|
|
if (!_formKey.currentState!.validate()) return;
|
|
|
|
try {
|
|
await ref
|
|
.read(authControllerProvider.notifier)
|
|
.register(
|
|
RegisterUser(
|
|
businessName: _businessNameController.text.trim(),
|
|
ownerName: _nameController.text.trim(),
|
|
phoneNumber: _phoneNumberController.text.trim(),
|
|
email: _emailController.text.trim(),
|
|
password: _passwordController.text.trim(),
|
|
passwordConfirmation: _passwordConfirmController.text.trim(),
|
|
),
|
|
);
|
|
|
|
await ref
|
|
.read(authControllerProvider.notifier)
|
|
.login(
|
|
LoginUser(
|
|
identifier: _phoneNumberController.text.trim(),
|
|
password: _passwordController.text.trim(),
|
|
),
|
|
);
|
|
|
|
if (!mounted) return;
|
|
|
|
await _setCurrentOutlet();
|
|
|
|
await _setCurrentUser();
|
|
|
|
CustomSnackbar.showSuccess(context, "Berhasil login");
|
|
context.goNamed(AppRoute.homeScreen);
|
|
} on ServerException catch (e) {
|
|
if (!mounted) ;
|
|
|
|
CustomSnackbar.showError(context, e.message);
|
|
} catch (e, st) {
|
|
LogMessage.log.e(e.toString(), error: e, stackTrace: st);
|
|
CustomSnackbar.showError(context, "Ups, terjadi kesalahan");
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
final bool isTablet = 100.w >= 600;
|
|
|
|
final authControllerState = ref.watch(authControllerProvider);
|
|
|
|
final isLoading = authControllerState.isLoading;
|
|
|
|
return SafeArea(
|
|
top: false,
|
|
bottom: true,
|
|
right: false,
|
|
left: false,
|
|
child: Scaffold(
|
|
backgroundColor: Colors.white,
|
|
body: SafeArea(
|
|
child: SingleChildScrollView(
|
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 5.h),
|
|
child: Form(
|
|
key: _formKey,
|
|
child: Column(
|
|
children: [
|
|
Image.asset(AppAsset.LOGO_UPDATE, height: 12.h),
|
|
|
|
SizedBox(height: 2.5.h),
|
|
|
|
Text(
|
|
"Daftar Akun",
|
|
style: TextStyle(
|
|
fontSize: AppFontSize.large.sp,
|
|
fontWeight: FontWeight.bold,
|
|
color: AppColor.primaryColor,
|
|
),
|
|
),
|
|
SizedBox(height: 1.h),
|
|
Text(
|
|
"Setiap hal besar selalu dimulai dengan hal kecil. perkuat pondasi bisnimu dan gunakan strategi terbaik",
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(
|
|
fontSize: isTablet
|
|
? AppFontSize.medium.sp
|
|
: AppFontSize.small.sp,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
|
|
SizedBox(height: 4.h),
|
|
|
|
CustomTextFormField(
|
|
label: "Nama Usaha/Perusahaan",
|
|
hint: "Contoh: Ayam Gepok Pojok",
|
|
controller: _businessNameController,
|
|
prefixIcon: Icons.business_center_outlined,
|
|
validator: (value) => _validation(
|
|
value: value,
|
|
message: "Nama usaha belum diisi",
|
|
),
|
|
readOnly: isLoading,
|
|
),
|
|
|
|
SizedBox(height: 2.5.h),
|
|
|
|
CustomTextFormField(
|
|
label: "Nama Pemilik",
|
|
hint: "John Doe",
|
|
controller: _nameController,
|
|
prefixIcon: Icons.person_outline,
|
|
validator: (value) => _validation(
|
|
value: value,
|
|
message: "Nama pemilik belum diisi",
|
|
),
|
|
readOnly: isLoading,
|
|
),
|
|
|
|
SizedBox(height: 2.5.h),
|
|
|
|
CustomTextFormField(
|
|
label: "No. Whatsapp",
|
|
hint: "Contoh:081234xxxxxx",
|
|
keyboardType: TextInputType.phone,
|
|
controller: _phoneNumberController,
|
|
prefixIcon: Icons.phone_outlined,
|
|
validator: (value) => _validation(
|
|
value: value,
|
|
message: "No. Whatsapp belum diisi",
|
|
),
|
|
readOnly: isLoading,
|
|
),
|
|
|
|
SizedBox(height: 2.5.h),
|
|
|
|
CustomTextFormField(
|
|
label: "Email",
|
|
hint: "Opsional (Disarankan)",
|
|
keyboardType: TextInputType.emailAddress,
|
|
controller: _emailController,
|
|
prefixIcon: Icons.mail_outline_outlined,
|
|
validator: (value) =>
|
|
_validation(value: value, isEmail: true),
|
|
readOnly: isLoading,
|
|
),
|
|
|
|
SizedBox(height: 2.5.h),
|
|
|
|
CustomTextFormField(
|
|
label: "Password",
|
|
hint: "••••••••",
|
|
controller: _passwordController,
|
|
prefixIcon: Icons.lock_outline,
|
|
isObscure: _obscurePassword,
|
|
suffixIcon: _obscurePassword
|
|
? Icons.visibility_off
|
|
: Icons.visibility,
|
|
suffixPressed: () {
|
|
setState(() {
|
|
_obscurePassword = !_obscurePassword;
|
|
});
|
|
},
|
|
validator: (value) => _validation(
|
|
value: value,
|
|
message: "Password belum diisi",
|
|
isPassword: true,
|
|
),
|
|
readOnly: isLoading,
|
|
),
|
|
|
|
SizedBox(height: 2.5.h),
|
|
|
|
CustomTextFormField(
|
|
label: "Konfirmasi Password",
|
|
hint: "••••••••",
|
|
controller: _passwordConfirmController,
|
|
prefixIcon: Icons.lock_outline,
|
|
isObscure: _obscurePasswordConfirm,
|
|
suffixIcon: _obscurePasswordConfirm
|
|
? Icons.visibility_off
|
|
: Icons.visibility,
|
|
suffixPressed: () {
|
|
setState(() {
|
|
_obscurePasswordConfirm = !_obscurePasswordConfirm;
|
|
});
|
|
},
|
|
validator: (value) => _validation(
|
|
value: value,
|
|
message: "Konfirmasi password belum diisi",
|
|
isPasswordConfirm: true,
|
|
),
|
|
readOnly: isLoading,
|
|
),
|
|
|
|
SizedBox(height: 2.5.h),
|
|
|
|
ElevatedButton(
|
|
onPressed: isLoading ? null : _register,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColor.primaryColor,
|
|
minimumSize: Size(double.infinity, 7.h),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(3.w),
|
|
),
|
|
elevation: 2,
|
|
disabledBackgroundColor: Colors.grey.shade300,
|
|
),
|
|
child: Text(
|
|
"Daftar Sekarang",
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: AppFontSize.medium.sp,
|
|
),
|
|
),
|
|
),
|
|
|
|
SizedBox(height: 4.h),
|
|
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
"Sudah punya akun? ",
|
|
style: TextStyle(
|
|
fontSize: isTablet
|
|
? AppFontSize.medium.sp
|
|
: AppFontSize.small.sp,
|
|
),
|
|
),
|
|
GestureDetector(
|
|
onTap: () => context.canPop()
|
|
? context.pop()
|
|
: context.goNamed(AppRoute.ownerLoginScreen),
|
|
child: Text(
|
|
"Masuk",
|
|
style: TextStyle(
|
|
color: AppColor.primaryColor,
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: isTablet
|
|
? AppFontSize.medium.sp
|
|
: AppFontSize.small.sp,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
|
|
SizedBox(height: 2.5.h),
|
|
Text(
|
|
"Powered By P.T. Niaga Nusantara",
|
|
style: TextStyle(
|
|
color: Colors.grey.shade600,
|
|
fontWeight: FontWeight.w500,
|
|
fontSize: isTablet
|
|
? AppFontSize.medium.sp
|
|
: AppFontSize.small.sp,
|
|
),
|
|
),
|
|
SizedBox(height: 0.75.h),
|
|
Text(
|
|
"Versi 1.0.0",
|
|
style: TextStyle(
|
|
color: Colors.grey,
|
|
fontSize: isTablet
|
|
? AppFontSize.medium.sp
|
|
: AppFontSize.small.sp,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|