signup inprogress
parent
9c7c178f71
commit
14e845b18a
@ -0,0 +1,35 @@
|
|||||||
|
import 'package:test_sa/models/base.dart';
|
||||||
|
|
||||||
|
class Company extends Base {
|
||||||
|
final String? code;
|
||||||
|
final String? displayName;
|
||||||
|
|
||||||
|
Company({
|
||||||
|
this.code,
|
||||||
|
this.displayName,
|
||||||
|
}) : super(identifier: code, name: displayName);
|
||||||
|
|
||||||
|
factory Company.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Company(
|
||||||
|
code: json['code'],
|
||||||
|
displayName: json['displayName'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'code': code,
|
||||||
|
'displayName': displayName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is Company &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
code == other.code;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => code.hashCode;
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
class EmployeeERPModel {
|
||||||
|
final String? employeeId;
|
||||||
|
final String? fullName;
|
||||||
|
final String? email;
|
||||||
|
final String? mobileNumber;
|
||||||
|
final bool? existsInAtoms;
|
||||||
|
final String? message;
|
||||||
|
|
||||||
|
EmployeeERPModel({
|
||||||
|
this.employeeId,
|
||||||
|
this.fullName,
|
||||||
|
this.email,
|
||||||
|
this.mobileNumber,
|
||||||
|
this.existsInAtoms,
|
||||||
|
this.message,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory EmployeeERPModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return EmployeeERPModel(
|
||||||
|
employeeId: json['employeeId']?.toString(),
|
||||||
|
fullName: json['fullName'],
|
||||||
|
email: json['email'],
|
||||||
|
mobileNumber: json['mobileNumber'],
|
||||||
|
existsInAtoms: json['existsInAtoms'],
|
||||||
|
message: json['message'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'employeeId': employeeId,
|
||||||
|
'fullName': fullName,
|
||||||
|
'email': email,
|
||||||
|
'mobileNumber': mobileNumber,
|
||||||
|
'existsInAtoms': existsInAtoms,
|
||||||
|
'message': message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
import 'package:test_sa/models/base.dart';
|
||||||
|
|
||||||
|
class Group extends Base {
|
||||||
|
final String? code;
|
||||||
|
final String? displayName;
|
||||||
|
|
||||||
|
Group({
|
||||||
|
this.code,
|
||||||
|
this.displayName,
|
||||||
|
}) : super(identifier: code, name: displayName);
|
||||||
|
|
||||||
|
factory Group.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Group(
|
||||||
|
code: json['code'],
|
||||||
|
displayName: json['displayName'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'code': code,
|
||||||
|
'displayName': displayName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is Group &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
code == other.code;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => code.hashCode;
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
class SignUpRequestModel {
|
||||||
|
final String? companyCode;
|
||||||
|
final String? groupCode;
|
||||||
|
final String? employeeId;
|
||||||
|
final String? fullName;
|
||||||
|
final String? email;
|
||||||
|
final String? mobileNumber;
|
||||||
|
final String? extensionNumber;
|
||||||
|
final int? siteId;
|
||||||
|
final int? departmentId;
|
||||||
|
final String? role;
|
||||||
|
|
||||||
|
SignUpRequestModel({
|
||||||
|
this.companyCode,
|
||||||
|
this.groupCode,
|
||||||
|
this.employeeId,
|
||||||
|
this.fullName,
|
||||||
|
this.email,
|
||||||
|
this.mobileNumber,
|
||||||
|
this.extensionNumber,
|
||||||
|
this.siteId,
|
||||||
|
this.departmentId,
|
||||||
|
this.role,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'companyCode': companyCode,
|
||||||
|
'groupCode': groupCode,
|
||||||
|
'employeeId': employeeId,
|
||||||
|
'fullName': fullName,
|
||||||
|
'email': email,
|
||||||
|
'mobileNumber': mobileNumber,
|
||||||
|
'extensionNumber': extensionNumber,
|
||||||
|
'siteId': siteId,
|
||||||
|
'departmentId': departmentId,
|
||||||
|
'role': role,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:test_sa/modules/signup/models/company_model.dart';
|
||||||
|
import 'package:test_sa/providers/loading_list_notifier.dart';
|
||||||
|
|
||||||
|
class CompanyProvider extends LoadingListNotifier<Company> {
|
||||||
|
@override
|
||||||
|
Future getData({int? id}) async {
|
||||||
|
if (loading) return -2;
|
||||||
|
loading = true;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO: Replace with actual API call when available
|
||||||
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
|
||||||
|
items = [
|
||||||
|
Company(code: 'FM', displayName: 'Flow Medical (FM)'),
|
||||||
|
Company(code: 'FMS', displayName: 'Facility Management and Safety (FMS)'),
|
||||||
|
Company(code: 'Ajaji', displayName: 'Ajaji'),
|
||||||
|
];
|
||||||
|
|
||||||
|
stateCode = 200;
|
||||||
|
loading = false;
|
||||||
|
notifyListeners();
|
||||||
|
return 200;
|
||||||
|
} catch (error) {
|
||||||
|
loading = false;
|
||||||
|
stateCode = -1;
|
||||||
|
notifyListeners();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
import 'package:test_sa/modules/signup/models/group_model.dart';
|
||||||
|
import 'package:test_sa/providers/loading_list_notifier.dart';
|
||||||
|
|
||||||
|
class GroupProvider extends LoadingListNotifier<Group> {
|
||||||
|
@override
|
||||||
|
Future getData({int? id}) async {
|
||||||
|
if (loading) return -2;
|
||||||
|
loading = true;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO: Replace with actual API call when available
|
||||||
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
|
||||||
|
items = [
|
||||||
|
Group(code: 'HMG', displayName: 'HMG'),
|
||||||
|
Group(code: 'Non-HMG', displayName: 'Non-HMG'),
|
||||||
|
];
|
||||||
|
|
||||||
|
stateCode = 200;
|
||||||
|
loading = false;
|
||||||
|
notifyListeners();
|
||||||
|
return 200;
|
||||||
|
} catch (error) {
|
||||||
|
loading = false;
|
||||||
|
stateCode = -1;
|
||||||
|
notifyListeners();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,100 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
|
import 'package:test_sa/controllers/api_routes/api_manager.dart';
|
||||||
|
import 'package:test_sa/controllers/api_routes/urls.dart';
|
||||||
|
import 'package:test_sa/modules/signup/models/employee_erp_model.dart';
|
||||||
|
import 'package:test_sa/modules/signup/models/signup_request_model.dart';
|
||||||
|
|
||||||
|
class SignUpProvider extends ChangeNotifier {
|
||||||
|
bool _loading = false;
|
||||||
|
bool get loading => _loading;
|
||||||
|
|
||||||
|
set loading(bool value) {
|
||||||
|
_loading = value;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
EmployeeERPModel? _employeeData;
|
||||||
|
EmployeeERPModel? get employeeData => _employeeData;
|
||||||
|
|
||||||
|
String? _errorMessage;
|
||||||
|
String? get errorMessage => _errorMessage;
|
||||||
|
|
||||||
|
/// Fetch employee details from ERP
|
||||||
|
Future<EmployeeERPModel?> getEmployeeFromERP(String employeeId) async {
|
||||||
|
if (loading) return null;
|
||||||
|
|
||||||
|
loading = true;
|
||||||
|
_errorMessage = null;
|
||||||
|
_employeeData = null;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final url = '${URLs.signUpGetEmployeeFromERP}?employeeId=$employeeId';
|
||||||
|
Response response = await ApiManager.instance.get(url, enableToastMessage: false);
|
||||||
|
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||||
|
final data = json.decode(response.body);
|
||||||
|
_employeeData = EmployeeERPModel.fromJson(data['data']);
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
notifyListeners();
|
||||||
|
return _employeeData;
|
||||||
|
} else {
|
||||||
|
final data = json.decode(response.body);
|
||||||
|
_errorMessage = data['message'] ?? 'Failed to fetch employee details';
|
||||||
|
loading = false;
|
||||||
|
notifyListeners();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
_errorMessage = 'Failed to fetch employee details';
|
||||||
|
loading = false;
|
||||||
|
notifyListeners();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Submit signup request
|
||||||
|
Future<bool> submitSignUpRequest(SignUpRequestModel request) async {
|
||||||
|
if (loading) return false;
|
||||||
|
|
||||||
|
loading = true;
|
||||||
|
_errorMessage = null;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Response response = await ApiManager.instance.post(
|
||||||
|
URLs.signUpSubmit,
|
||||||
|
body: request.toJson(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||||
|
loading = false;
|
||||||
|
notifyListeners();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
final data = json.decode(response.body);
|
||||||
|
_errorMessage = data['message'] ?? 'Failed to submit signup request';
|
||||||
|
loading = false;
|
||||||
|
notifyListeners();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
_errorMessage = 'Failed to submit signup request';
|
||||||
|
loading = false;
|
||||||
|
notifyListeners();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
_loading = false;
|
||||||
|
_employeeData = null;
|
||||||
|
_errorMessage = null;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,479 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:test_sa/controllers/validator/validator.dart';
|
||||||
|
import 'package:test_sa/extensions/int_extensions.dart';
|
||||||
|
import 'package:test_sa/extensions/text_extensions.dart';
|
||||||
|
import 'package:test_sa/models/lookup.dart';
|
||||||
|
import 'package:test_sa/models/new_models/site.dart';
|
||||||
|
import 'package:test_sa/modules/signup/models/company_model.dart';
|
||||||
|
import 'package:test_sa/modules/signup/models/group_model.dart';
|
||||||
|
import 'package:test_sa/modules/signup/models/signup_request_model.dart';
|
||||||
|
import 'package:test_sa/modules/signup/providers/company_provider.dart';
|
||||||
|
import 'package:test_sa/modules/signup/providers/group_provider.dart';
|
||||||
|
import 'package:test_sa/modules/signup/providers/signup_provider.dart';
|
||||||
|
import 'package:test_sa/new_views/app_style/app_color.dart';
|
||||||
|
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
|
||||||
|
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
|
||||||
|
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
|
||||||
|
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
|
||||||
|
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
|
||||||
|
import 'package:test_sa/providers/department_provider.dart';
|
||||||
|
import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
|
||||||
|
|
||||||
|
class SignUpScreen extends StatefulWidget {
|
||||||
|
static const String routeName = "/signup_screen";
|
||||||
|
|
||||||
|
const SignUpScreen({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SignUpScreen> createState() => _SignUpScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SignUpScreenState extends State<SignUpScreen> {
|
||||||
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
late CompanyProvider _companyProvider;
|
||||||
|
late GroupProvider _groupProvider;
|
||||||
|
late SignUpProvider _signUpProvider;
|
||||||
|
late DepartmentProvider _departmentProvider;
|
||||||
|
|
||||||
|
// Form field controllers
|
||||||
|
final TextEditingController _employeeIdController = TextEditingController();
|
||||||
|
final TextEditingController _fullNameController = TextEditingController();
|
||||||
|
final TextEditingController _emailController = TextEditingController();
|
||||||
|
final TextEditingController _mobileController = TextEditingController();
|
||||||
|
final TextEditingController _extensionController = TextEditingController();
|
||||||
|
final TextEditingController _roleController = TextEditingController();
|
||||||
|
|
||||||
|
// Selected values
|
||||||
|
Company? _selectedCompany;
|
||||||
|
Group? _selectedGroup;
|
||||||
|
Site? _selectedSite;
|
||||||
|
Lookup? _selectedDepartment;
|
||||||
|
|
||||||
|
bool _isHMGGroup = false;
|
||||||
|
bool _employeeFetched = false;
|
||||||
|
bool _isSubmitting = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_companyProvider.getData();
|
||||||
|
_groupProvider.getData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_employeeIdController.dispose();
|
||||||
|
_fullNameController.dispose();
|
||||||
|
_emailController.dispose();
|
||||||
|
_mobileController.dispose();
|
||||||
|
_extensionController.dispose();
|
||||||
|
_roleController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
_companyProvider = Provider.of<CompanyProvider>(context);
|
||||||
|
_groupProvider = Provider.of<GroupProvider>(context);
|
||||||
|
_signUpProvider = Provider.of<SignUpProvider>(context);
|
||||||
|
_departmentProvider = Provider.of<DepartmentProvider>(context);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColor.scaffoldBackground(context),
|
||||||
|
appBar: const DefaultAppBar(title: "Sign Up"),
|
||||||
|
body: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.all(16.toScreenWidth),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildCompanyDropdown(),
|
||||||
|
16.height,
|
||||||
|
_buildGroupDropdown(),
|
||||||
|
16.height,
|
||||||
|
if (_selectedGroup != null) ..._buildDynamicFields(),
|
||||||
|
24.height,
|
||||||
|
_buildSubmitButton(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCompanyDropdown() {
|
||||||
|
return SingleItemDropDownMenu<Company, CompanyProvider>(
|
||||||
|
context: context,
|
||||||
|
title: "Company",
|
||||||
|
initialValue: _selectedCompany,
|
||||||
|
showAsFullScreenDialog: false,
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
setState(() {
|
||||||
|
_selectedCompany = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Company is required";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildGroupDropdown() {
|
||||||
|
return SingleItemDropDownMenu<Group, GroupProvider>(
|
||||||
|
context: context,
|
||||||
|
title: "Group",
|
||||||
|
initialValue: _selectedGroup,
|
||||||
|
showAsFullScreenDialog: false,
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
setState(() {
|
||||||
|
_selectedGroup = value;
|
||||||
|
_isHMGGroup = value?.code == 'HMG';
|
||||||
|
_employeeFetched = false;
|
||||||
|
_clearForm();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Group is required";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> _buildDynamicFields() {
|
||||||
|
if (_isHMGGroup) {
|
||||||
|
return [
|
||||||
|
_buildEmployeeIdField(),
|
||||||
|
16.height,
|
||||||
|
if (_employeeFetched) ...[
|
||||||
|
_buildReadOnlyField("Full Name", _fullNameController),
|
||||||
|
16.height,
|
||||||
|
_buildReadOnlyField("Email Address", _emailController),
|
||||||
|
16.height,
|
||||||
|
_buildReadOnlyField("Mobile Number", _mobileController),
|
||||||
|
16.height,
|
||||||
|
_buildExtensionField(),
|
||||||
|
16.height,
|
||||||
|
_buildSiteDropdown(),
|
||||||
|
16.height,
|
||||||
|
_buildDepartmentDropdown(),
|
||||||
|
16.height,
|
||||||
|
_buildRoleField(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
_buildReadOnlyEmployeeIdField(),
|
||||||
|
16.height,
|
||||||
|
_buildFullNameField(),
|
||||||
|
16.height,
|
||||||
|
_buildEmailField(),
|
||||||
|
16.height,
|
||||||
|
_buildMobileField(),
|
||||||
|
16.height,
|
||||||
|
_buildExtensionField(),
|
||||||
|
16.height,
|
||||||
|
_buildSiteDropdown(),
|
||||||
|
16.height,
|
||||||
|
_buildDepartmentDropdown(),
|
||||||
|
16.height,
|
||||||
|
_buildRoleField(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildEmployeeIdField() {
|
||||||
|
return AppTextFormField(
|
||||||
|
controller: _employeeIdController,
|
||||||
|
labelText: "Employee ID",
|
||||||
|
hintText: "Enter Employee ID",
|
||||||
|
textInputType: TextInputType.number,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) return "Employee ID is required";
|
||||||
|
if (!Validator.isNumeric(value)) return "Employee ID must be numeric";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
onChange: (value) {
|
||||||
|
if (value.isNotEmpty && Validator.isNumeric(value)) {
|
||||||
|
_fetchEmployeeDetails(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildReadOnlyEmployeeIdField() {
|
||||||
|
return AppTextFormField(
|
||||||
|
initialValue: "Will be generated after admin approval",
|
||||||
|
labelText: "Employee ID",
|
||||||
|
enable: false,
|
||||||
|
backgroundColor: AppColor.disableFieldBackground(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildReadOnlyField(String label, TextEditingController controller) {
|
||||||
|
return AppTextFormField(
|
||||||
|
controller: controller,
|
||||||
|
labelText: label,
|
||||||
|
enable: false,
|
||||||
|
backgroundColor: AppColor.disableFieldBackground(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFullNameField() {
|
||||||
|
return AppTextFormField(
|
||||||
|
controller: _fullNameController,
|
||||||
|
labelText: "Full Name",
|
||||||
|
hintText: "Enter Full Name",
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) return "Full Name is required";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildEmailField() {
|
||||||
|
return AppTextFormField(
|
||||||
|
controller: _emailController,
|
||||||
|
labelText: "Email Address",
|
||||||
|
hintText: "Enter Email Address",
|
||||||
|
textInputType: TextInputType.emailAddress,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) return "Email is required";
|
||||||
|
if (!Validator.isEmail(value)) return "Invalid email format";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMobileField() {
|
||||||
|
return AppTextFormField(
|
||||||
|
controller: _mobileController,
|
||||||
|
labelText: "Mobile Number",
|
||||||
|
hintText: "Enter Mobile Number",
|
||||||
|
textInputType: TextInputType.phone,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) return "Mobile Number is required";
|
||||||
|
if (!Validator.isPhoneNumber(value)) return "Invalid mobile number";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildExtensionField() {
|
||||||
|
return AppTextFormField(
|
||||||
|
controller: _extensionController,
|
||||||
|
labelText: "Extension Number",
|
||||||
|
hintText: "Enter Extension Number (Optional)",
|
||||||
|
textInputType: TextInputType.number,
|
||||||
|
validator: (value) {
|
||||||
|
if (value != null && value.isNotEmpty && !Validator.isNumeric(value)) {
|
||||||
|
return "Extension must be numeric";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSiteDropdown() {
|
||||||
|
return SingleItemDropDownMenu<Site, SiteProvider>(
|
||||||
|
context: context,
|
||||||
|
title: "Site",
|
||||||
|
initialValue: _selectedSite,
|
||||||
|
showAsFullScreenDialog: false,
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
setState(() {
|
||||||
|
_selectedSite = value;
|
||||||
|
_selectedDepartment = null;
|
||||||
|
});
|
||||||
|
if (value != null) {
|
||||||
|
_departmentProvider.getData(id: value.id?.toInt());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Site is required";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDepartmentDropdown() {
|
||||||
|
return SingleItemDropDownMenu<Lookup, DepartmentProvider>(
|
||||||
|
context: context,
|
||||||
|
title: "Department",
|
||||||
|
initialValue: _selectedDepartment,
|
||||||
|
showAsFullScreenDialog: false,
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
onSelect: (value) {
|
||||||
|
setState(() {
|
||||||
|
_selectedDepartment = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) return "Department is required";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildRoleField() {
|
||||||
|
return AppTextFormField(
|
||||||
|
controller: _roleController,
|
||||||
|
labelText: "Role",
|
||||||
|
hintText: "Enter Role",
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) return "Role is required";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSubmitButton() {
|
||||||
|
return AppFilledButton(
|
||||||
|
label: "Submit",
|
||||||
|
maxWidth: true,
|
||||||
|
loading: _isSubmitting,
|
||||||
|
disableButton: _isSubmitting,
|
||||||
|
onPressed: _submitForm,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchEmployeeDetails(String employeeId) async {
|
||||||
|
final employee = await _signUpProvider.getEmployeeFromERP(employeeId);
|
||||||
|
|
||||||
|
if (employee != null) {
|
||||||
|
if (employee.existsInAtoms == true) {
|
||||||
|
if (mounted) {
|
||||||
|
_showAlreadyExistsDialog();
|
||||||
|
}
|
||||||
|
_clearForm();
|
||||||
|
_employeeIdController.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_employeeFetched = true;
|
||||||
|
_fullNameController.text = employee.fullName ?? '';
|
||||||
|
_emailController.text = employee.email ?? '';
|
||||||
|
_mobileController.text = employee.mobileNumber ?? '';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_employeeFetched = false;
|
||||||
|
});
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: _signUpProvider.errorMessage ?? "Failed to fetch employee details",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showAlreadyExistsDialog() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
backgroundColor: AppColor.background(context),
|
||||||
|
title: "Account Exists".bodyText(context),
|
||||||
|
content: "Already you have an account on Atoms".bodyText(context),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: "OK".bodyText(context).custom(color: AppColor.primary10),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clearForm() {
|
||||||
|
_fullNameController.clear();
|
||||||
|
_emailController.clear();
|
||||||
|
_mobileController.clear();
|
||||||
|
_extensionController.clear();
|
||||||
|
_roleController.clear();
|
||||||
|
_selectedSite = null;
|
||||||
|
_selectedDepartment = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _submitForm() async {
|
||||||
|
if (!_formKey.currentState!.validate()) return;
|
||||||
|
|
||||||
|
if (_isHMGGroup && !_employeeFetched) {
|
||||||
|
Fluttertoast.showToast(msg: "Please enter a valid Employee ID");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isSubmitting = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (context) => const AppLazyLoading(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final request = SignUpRequestModel(
|
||||||
|
companyCode: _selectedCompany?.code,
|
||||||
|
groupCode: _selectedGroup?.code,
|
||||||
|
employeeId: _isHMGGroup ? _employeeIdController.text : null,
|
||||||
|
fullName: _fullNameController.text,
|
||||||
|
email: _emailController.text,
|
||||||
|
mobileNumber: _mobileController.text,
|
||||||
|
extensionNumber: _extensionController.text.isEmpty ? null : _extensionController.text,
|
||||||
|
siteId: _selectedSite?.id?.toInt(),
|
||||||
|
departmentId: _selectedDepartment?.id,
|
||||||
|
role: _roleController.text,
|
||||||
|
);
|
||||||
|
|
||||||
|
final success = await _signUpProvider.submitSignUpRequest(request);
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.pop(context); // Close loading dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isSubmitting = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
if (mounted) {
|
||||||
|
_showSuccessDialog();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: _signUpProvider.errorMessage ?? "Failed to submit signup request",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showSuccessDialog() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
backgroundColor: AppColor.background(context),
|
||||||
|
title: "Success".bodyText(context),
|
||||||
|
content: "Your signup request has been submitted successfully. It will be reviewed by the Human Resources Admin."
|
||||||
|
.bodyText(context),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context); // Close dialog
|
||||||
|
Navigator.pop(context); // Go back to login
|
||||||
|
},
|
||||||
|
child: "OK".bodyText(context).custom(color: AppColor.primary10),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue