taxgilde/lib/auth/signup_screen.dart
2026-04-15 12:32:30 +05:30

333 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get/get.dart';
import 'package:taxglide/consts/app_asstes.dart';
import 'package:taxglide/consts/app_colors.dart';
import 'package:taxglide/consts/comman_button.dart';
import 'package:taxglide/consts/comman_container_auth.dart';
import 'package:taxglide/consts/comman_textformfileds.dart';
import 'package:taxglide/consts/validation_popup.dart';
import 'package:taxglide/controller/api_contoller.dart';
import 'package:taxglide/router/consts_routers.dart';
import 'package:taxglide/consts/app_style.dart';
class SignupScreen extends ConsumerStatefulWidget {
const SignupScreen({super.key});
@override
ConsumerState<SignupScreen> createState() => _SignupScreenState();
}
class _SignupScreenState extends ConsumerState<SignupScreen> {
final ValidationPopup _validationPopup = ValidationPopup();
final TextEditingController _nameController = TextEditingController();
final TextEditingController _mobileController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
@override
void initState() {
super.initState();
// Get arguments from navigation if available
final args = Get.arguments;
if (args != null && args is Map<String, dynamic>) {
_nameController.text = args['name'] ?? '';
_emailController.text = args['email'] ?? '';
_mobileController.text = args['mobile'] ?? '';
}
}
// Error state tracking
bool _nameError = false;
bool _mobileError = false;
bool _emailError = false;
@override
Widget build(BuildContext context) {
// Listen to signup state
final signupState = ref.watch(signupProvider);
// Handle API response
ref.listen<AsyncValue<Map<String, dynamic>>>(signupProvider, (
previous,
next,
) {
next.when(
data: (response) {
if (response.isNotEmpty) {
if (response['success'] == true) {
_validationPopup.showSuccessMessage(
context,
"Sign up successful! OTP sent to your mobile.",
);
// Navigate to RegisterOtpScreen with all data
Future.delayed(const Duration(milliseconds: 500), () {
Get.toNamed(
ConstRouters.registerOtp,
arguments: {
'name': _nameController.text,
'email': _emailController.text,
'mobile': _mobileController.text,
},
);
});
} else {
_validationPopup.showErrorMessage(
context,
response['error'] ?? 'Signup failed',
);
}
}
},
error: (error, stackTrace) {
_validationPopup.showErrorMessage(
context,
'An error occurred: ${error.toString()}',
);
},
loading: () {},
);
});
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
Get.offAllNamed(ConstRouters.login);
},
child: Scaffold(
body: Stack(
children: [
// 🌈 Background gradient
Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFFFF8F0),
Color(0xFFEBC894),
Color(0xFFE8DAF2),
Color(0xFFB49EF4),
],
stops: [0.0, 0.3, 0.6, 1.0],
),
),
),
// 📜 Scrollable content
SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: Center(
child: CommonContainerAuth(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset(
AppAssets.taxgildelogoauth,
width: 141,
height: 100,
fit: BoxFit.contain,
),
const SizedBox(height: 20),
// 🟣 Title
Text(
"Sign Up",
textAlign: TextAlign.center,
style: AppTextStyles.semiBold.copyWith(
fontSize: 32,
height: 1.3,
letterSpacing: 0.01 * 32,
color: AppColors.authheading,
),
),
const SizedBox(height: 25),
// 👤 Name Field
Align(
alignment: Alignment.centerLeft,
child: Text(
"Name*",
style: AppTextStyles.semiBold.copyWith(
fontSize: 14,
color: AppColors.authheading,
),
),
),
const SizedBox(height: 8),
CommanTextFormField(
hintText: 'Enter Company Name',
controller: _nameController,
hasError: _nameError,
onChanged: (value) {
if (_nameError && value.isNotEmpty) {
setState(() {
_nameError = false;
});
}
},
),
const SizedBox(height: 10),
// 📱 Mobile Number Field
Align(
alignment: Alignment.centerLeft,
child: Text(
"Contact Number *",
style: AppTextStyles.semiBold.copyWith(
fontSize: 14,
color: AppColors.authheading,
),
),
),
const SizedBox(height: 8),
CommanTextFormField(
hintText: 'Enter Contact Number',
controller: _mobileController,
hasError: _mobileError,
keyboardType: TextInputType.phone,
onChanged: (value) {
if (_mobileError && value.isNotEmpty) {
setState(() {
_mobileError = false;
});
}
},
),
const SizedBox(height: 10),
// 📧 Email Field
Align(
alignment: Alignment.centerLeft,
child: Text(
"Email *",
style: AppTextStyles.semiBold.copyWith(
fontSize: 14,
color: AppColors.authheading,
),
),
),
const SizedBox(height: 8),
CommanTextFormField(
hintText: 'Enter Email ID',
controller: _emailController,
hasError: _emailError,
keyboardType: TextInputType.emailAddress,
onChanged: (value) {
if (_emailError && value.isNotEmpty) {
setState(() {
_emailError = false;
});
}
},
),
const SizedBox(height: 30),
// ✅ Submit Button
signupState.isLoading
? const CircularProgressIndicator()
: CommanButton(
text: "Submit",
onPressed: () {
_handleSignup();
},
),
],
),
),
),
),
),
],
),
),
);
}
void _handleSignup() {
// Reset all errors first
setState(() {
_nameError = false;
_mobileError = false;
_emailError = false;
});
bool hasError = false;
// Validate name
if (_nameController.text.isEmpty) {
setState(() {
_nameError = true;
});
hasError = true;
}
// Validate mobile
if (_mobileController.text.isEmpty) {
setState(() {
_mobileError = true;
});
hasError = true;
} else if (!_validationPopup.validateMobileNumber(
context,
_mobileController.text,
)) {
setState(() {
_mobileError = true;
});
hasError = true;
}
// Validate email - NOW WITH FORMAT CHECK
if (_emailController.text.isEmpty) {
setState(() {
_emailError = true;
});
hasError = true;
} else if (!_validationPopup.validateEmail(
context,
_emailController.text,
)) {
setState(() {
_emailError = true;
});
hasError = true;
}
// Show error message if any field has error
if (hasError) {
_validationPopup.showErrorMessage(
context,
"Please fill all required fields correctly",
);
return;
}
// All validations passed - call API
ref
.read(signupProvider.notifier)
.signup(
_nameController.text,
_mobileController.text,
_emailController.text,
);
}
@override
void dispose() {
_nameController.dispose();
_mobileController.dispose();
_emailController.dispose();
super.dispose();
}
}