<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="app_color">#011842</color>
<color name="editBackgroundColor">#E4EFF9</color>
<color name="blue">#0000FF</color>
<color name="transparent">#CCFFFFFF</color>
<color name="grey">#696969</color>\
<color name="red">#EC454C</color>
<color name="brown">#663300</color>
<color name="green">#27ae60</color>
<color name="app_color_opacity">#26011842</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="app_color">#011842</color>
<color name="editBackgroundColor">#E4EFF9</color>
<color name="blue">#0000FF</color>
<color name="transparent">#CCFFFFFF</color>
<color name="grey">#696969</color>\
<color name="red">#EC454C</color>
<color name="brown">#663300</color>
<color name="green">#27ae60</color>
<color name="app_color_opacity">#26011842</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="images/"/>
</paths>
...@@ -42,6 +42,7 @@ class RequestList { ...@@ -42,6 +42,7 @@ class RequestList {
String? checkOutTime; String? checkOutTime;
String? status; String? status;
String? requestedDatetime; String? requestedDatetime;
String? employeeName;
RequestList( RequestList(
{this.id, {this.id,
...@@ -53,7 +54,9 @@ class RequestList { ...@@ -53,7 +54,9 @@ class RequestList {
this.chechOutType, this.chechOutType,
this.checkOutTime, this.checkOutTime,
this.status, this.status,
this.requestedDatetime}); this.requestedDatetime,
this.employeeName,
});
RequestList.fromJson(Map<String, dynamic> json) { RequestList.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
...@@ -66,6 +69,7 @@ class RequestList { ...@@ -66,6 +69,7 @@ class RequestList {
checkOutTime = json['check_out_time']; checkOutTime = json['check_out_time'];
status = json['status']; status = json['status'];
requestedDatetime = json['requested_datetime']; requestedDatetime = json['requested_datetime'];
employeeName = json['employee_name'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
...@@ -80,6 +84,7 @@ class RequestList { ...@@ -80,6 +84,7 @@ class RequestList {
data['check_out_time'] = this.checkOutTime; data['check_out_time'] = this.checkOutTime;
data['status'] = this.status; data['status'] = this.status;
data['requested_datetime'] = this.requestedDatetime; data['requested_datetime'] = this.requestedDatetime;
data['employee_name'] = this.employeeName;
return data; return data;
} }
} }
...@@ -38,6 +38,8 @@ class RequestList { ...@@ -38,6 +38,8 @@ class RequestList {
String? toPeriod; String? toPeriod;
String? status; String? status;
String? leaveType; String? leaveType;
String? rowColor;
String? employeeName;
RequestList( RequestList(
...@@ -50,6 +52,8 @@ class RequestList { ...@@ -50,6 +52,8 @@ class RequestList {
toPeriod = json['to_period']; toPeriod = json['to_period'];
status = json['status']; status = json['status'];
leaveType = json["leave_type"]; leaveType = json["leave_type"];
rowColor = json["row_colur"];
employeeName = json["employee_name"];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
...@@ -60,6 +64,8 @@ class RequestList { ...@@ -60,6 +64,8 @@ class RequestList {
data['to_period'] = this.toPeriod; data['to_period'] = this.toPeriod;
data['status'] = this.status; data['status'] = this.status;
data["leave_type"] = this.leaveType; data["leave_type"] = this.leaveType;
data["row_colur"] = this.rowColor;
data["employee_name"] = this.employeeName;
return data; return data;
} }
} }
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../Models/hrmModels/leaveApplicationDetailsResponse.dart'; import '../../Models/hrmModels/leaveApplicationDetailsResponse.dart';
import '../../Models/ordersModels/commonResponse.dart';
import '../../services/api_calling.dart'; import '../../services/api_calling.dart';
import '../HomeScreenNotifier.dart'; import '../HomeScreenNotifier.dart';
...@@ -9,6 +11,11 @@ class LeaveApplicationDetailsProvider extends ChangeNotifier { ...@@ -9,6 +11,11 @@ class LeaveApplicationDetailsProvider extends ChangeNotifier {
leaveApplicationDetailsResponse? _response; leaveApplicationDetailsResponse? _response;
bool _isLoading = false; bool _isLoading = false;
String? _errorMessage; String? _errorMessage;
bool _isSubmitting = false;
bool get isSubmitting => _isSubmitting;
CommonResponse? _StatusResponse;
CommonResponse? get Response => _StatusResponse;
leaveApplicationDetailsResponse? get response => _response; leaveApplicationDetailsResponse? get response => _response;
bool get isLoading => _isLoading; bool get isLoading => _isLoading;
...@@ -43,6 +50,60 @@ class LeaveApplicationDetailsProvider extends ChangeNotifier { ...@@ -43,6 +50,60 @@ class LeaveApplicationDetailsProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<void> leaveRequestRejectApprove(
BuildContext context, {
required String mode,
required String type,
required String remarks,
required String id,
}) async {
_isSubmitting = true;
_errorMessage = null;
_StatusResponse = null;
notifyListeners();
try {
final homeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
final result = await ApiCalling.leaveRequestRejectApproveAPI(
homeProvider.session,
homeProvider.empId,
mode,
type,
remarks,
id,
);
if (result != null) {
_StatusResponse = result;
if (result.error != null && result.error!.isNotEmpty) {
_errorMessage = result.error;
} else {
// Show success snack bar
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
"Leave request ${type.toLowerCase()} successfully.",
),
backgroundColor: Colors.green,
behavior: SnackBarBehavior.floating,
),
);
}
} else {
_errorMessage = "Failed to $type leave request!";
}
} catch (e) {
_errorMessage = "Error while processing leave request: $e";
}
_isSubmitting = false;
notifyListeners();
}
/// Clear the current response data /// Clear the current response data
void clearData() { void clearData() {
_response = null; _response = null;
......
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:generp/Models/hrmModels/attendanceRequestDetailsResponse.dart'; import 'package:generp/Models/hrmModels/attendanceRequestDetailsResponse.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../Models/hrmModels/attendanceRequestListResponse.dart'; import '../../Models/hrmModels/attendanceRequestListResponse.dart';
import '../../Models/ordersModels/commonResponse.dart';
import '../../services/api_calling.dart'; import '../../services/api_calling.dart';
import '../HomeScreenNotifier.dart'; import '../HomeScreenNotifier.dart';
...@@ -12,6 +14,11 @@ class AttendanceDetailsProvider extends ChangeNotifier { ...@@ -12,6 +14,11 @@ class AttendanceDetailsProvider extends ChangeNotifier {
attendanceRequestDetailsResponse? _response; attendanceRequestDetailsResponse? _response;
bool _isLoading = false; bool _isLoading = false;
String? _errorMessage; String? _errorMessage;
bool _isSubmitting = false;
bool get isSubmitting => _isSubmitting;
CommonResponse? _RejectResponse;
CommonResponse? get addResponse => _RejectResponse;
attendanceRequestDetailsResponse? get response => _response; attendanceRequestDetailsResponse? get response => _response;
bool get isLoading => _isLoading; bool get isLoading => _isLoading;
...@@ -39,4 +46,51 @@ class AttendanceDetailsProvider extends ChangeNotifier { ...@@ -39,4 +46,51 @@ class AttendanceDetailsProvider extends ChangeNotifier {
_isLoading = false; _isLoading = false;
notifyListeners(); notifyListeners();
} }
Future<void> rejectApproveAttendanceRequest(
BuildContext context, {
required String mode,
required String type,
required String remarks,
required String id,
}) async {
_isSubmitting = true;
_errorMessage = null;
_RejectResponse = null;
notifyListeners();
try {
final homeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
print("############################+++++++++++++++++##########");
final result = await ApiCalling.attendanceRequestApproveRejectAPI(
homeProvider.session,
homeProvider.empId,
mode,
type,
remarks,
id,
);
if (result != null) {
_RejectResponse = result;
if (result.error != null && result.error!.isNotEmpty) {
_errorMessage = result.error;
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Attendance request rejected successfully."),
),
);
}
} else {
_errorMessage = "Failed to reject attendance request!";
}
} catch (e) {
_errorMessage = "Error rejecting attendance request: $e";
}
_isSubmitting = false;
notifyListeners();
}
} }
...@@ -123,10 +123,12 @@ class Attendancelistprovider extends ChangeNotifier { ...@@ -123,10 +123,12 @@ class Attendancelistprovider extends ChangeNotifier {
return null; // everything ok return null; // everything ok
} }
CommonResponse? _RejectResponse;
CommonResponse? get RejectResponse => _RejectResponse;
/// Fetch attendance request list with filters /// Fetch attendance request list with filters
Future<void> fetchAttendanceRequests(BuildContext context, Future<void> fetchAttendanceRequests(BuildContext context, mode,
{String? type, String? dateRange, DateTimeRange? customRange}) async { {String? type, String? dateRange, DateTimeRange? customRange}) async {
_isLoading = true; _isLoading = true;
_errorMessage = null; _errorMessage = null;
...@@ -152,6 +154,7 @@ class Attendancelistprovider extends ChangeNotifier { ...@@ -152,6 +154,7 @@ class Attendancelistprovider extends ChangeNotifier {
apiType, apiType,
dateParams['from']!, dateParams['from']!,
dateParams['to']!, dateParams['to']!,
mode
); );
debugPrint('Fetching attendance from: ${dateParams['from']} to: ${dateParams['to']}'); debugPrint('Fetching attendance from: ${dateParams['from']} to: ${dateParams['to']}');
...@@ -230,8 +233,52 @@ class Attendancelistprovider extends ChangeNotifier { ...@@ -230,8 +233,52 @@ class Attendancelistprovider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<void> rejectApproveAttendanceRequest({
required String session,
required String empId,
required String mode,
required String type,
required String remarks,
required String id,
}) async {
_isSubmitting = true;
_errorMessage = null;
_RejectResponse = null;
notifyListeners();
try {
final result = await ApiCalling.attendanceRequestApproveRejectAPI(
session,
empId,
mode,
type,
remarks,
id,
);
print("*********************************object");
if (result != null) {
_RejectResponse = result;
if (result.error != null && result.error!.isNotEmpty) {
_errorMessage = result.error;
} else {
debugPrint("Attendance request $type successfully.");
}
} else {
_errorMessage = "Failed to process attendance request!";
}
} catch (e) {
_errorMessage = "Error processing attendance request: $e";
}
_isSubmitting = false;
notifyListeners();
}
/// Apply filters coming from bottom sheet /// Apply filters coming from bottom sheet
void updateFiltersFromSheet( void updateFiltersFromSheet(
mode,
BuildContext context, { BuildContext context, {
required String type, required String type,
required String selectedValue, required String selectedValue,
...@@ -243,6 +290,7 @@ class Attendancelistprovider extends ChangeNotifier { ...@@ -243,6 +290,7 @@ class Attendancelistprovider extends ChangeNotifier {
fetchAttendanceRequests( fetchAttendanceRequests(
context, context,
mode,
type: _selectedType, type: _selectedType,
dateRange: _selectedDateRange, dateRange: _selectedDateRange,
customRange: _customDateRange, customRange: _customDateRange,
...@@ -250,13 +298,13 @@ class Attendancelistprovider extends ChangeNotifier { ...@@ -250,13 +298,13 @@ class Attendancelistprovider extends ChangeNotifier {
} }
/// Set type filter and refresh data /// Set type filter and refresh data
void setTypeFilter(BuildContext context, String type) { void setTypeFilter(BuildContext context, String type, mode) {
_selectedType = type; _selectedType = type;
fetchAttendanceRequests(context); fetchAttendanceRequests(context, mode);
} }
/// Set date range filter and refresh data /// Set date range filter and refresh data
void setDateRangeFilter(BuildContext context, String dateRange, void setDateRangeFilter(BuildContext context, String dateRange, mode,
{DateTimeRange? customRange}) { {DateTimeRange? customRange}) {
_selectedDateRange = dateRange; _selectedDateRange = dateRange;
if (customRange != null) { if (customRange != null) {
...@@ -264,24 +312,24 @@ class Attendancelistprovider extends ChangeNotifier { ...@@ -264,24 +312,24 @@ class Attendancelistprovider extends ChangeNotifier {
fromDateController.text = _formatDate(customRange.start); fromDateController.text = _formatDate(customRange.start);
toDateController.text = _formatDate(customRange.end); toDateController.text = _formatDate(customRange.end);
} }
fetchAttendanceRequests(context); fetchAttendanceRequests(context, mode);
} }
/// Clear all filters and refresh data /// Clear all filters and refresh data
void clearFilters(BuildContext context) { void clearFilters(BuildContext context, mode) {
_selectedType = "All"; _selectedType = "All";
_selectedDateRange = "This Month"; _selectedDateRange = "This Month";
_customDateRange = null; _customDateRange = null;
fromDateController.clear(); fromDateController.clear();
toDateController.clear(); toDateController.clear();
fetchAttendanceRequests(context); fetchAttendanceRequests(context, mode);
} }
/// Reset form and data /// Reset form and data
void resetForm(BuildContext context) { void resetForm(BuildContext context, mode) {
_response = null; _response = null;
_errorMessage = null; _errorMessage = null;
clearFilters(context); clearFilters(context, mode);
notifyListeners(); notifyListeners();
} }
...@@ -343,9 +391,10 @@ class Attendancelistprovider extends ChangeNotifier { ...@@ -343,9 +391,10 @@ class Attendancelistprovider extends ChangeNotifier {
} }
/// Apply filters and refresh data /// Apply filters and refresh data
void applyFilters(BuildContext context) { void applyFilters(BuildContext context, mode) {
fetchAttendanceRequests( fetchAttendanceRequests(
context, context,
mode,
type: _selectedType, type: _selectedType,
dateRange: _selectedDateRange, dateRange: _selectedDateRange,
customRange: _customDateRange, customRange: _customDateRange,
......
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../Models/hrmModels/hrmAccessiblePagesResponse.dart';
import '../../services/api_calling.dart';
import '../HomeScreenNotifier.dart';
class HrmAccessiblePagesProvider extends ChangeNotifier {
hrmAccessiblePagesResponse? _response;
bool _isLoading = false;
String? _errorMessage;
hrmAccessiblePagesResponse? get response => _response;
bool get isLoading => _isLoading;
String? get errorMessage => _errorMessage;
/// Fetch HRM Accessible Pages
Future<void> fetchAccessiblePages(BuildContext context) async {
_isLoading = true;
_errorMessage = null;
_response = null;
notifyListeners();
try {
final provider = Provider.of<HomescreenNotifier>(context, listen: false);
final result = await ApiCalling.hrmAccessiblePagesAPI(
provider.empId,
provider.session,
);
if (result != null) {
_response = result;
if (_response?.pagesAccessible == null || _response!.pagesAccessible!.isEmpty) {
_errorMessage = "No accessible pages found!";
}
} else {
_errorMessage = "No data found!";
}
} catch (e) {
_errorMessage = "Something went wrong: $e";
debugPrint("Error fetching HRM accessible pages: $e");
}
_isLoading = false;
notifyListeners();
}
/// Clear stored data
void clearData() {
_response = null;
_errorMessage = null;
notifyListeners();
}
}
...@@ -63,7 +63,7 @@ class LeaveApplicationListProvider extends ChangeNotifier { ...@@ -63,7 +63,7 @@ class LeaveApplicationListProvider extends ChangeNotifier {
DateTime? get selectedDate => _selectedDate; DateTime? get selectedDate => _selectedDate;
/// Fetch leave application list with filters /// Fetch leave application list with filters
Future<void> fetchLeaveApplications(BuildContext context, Future<void> fetchLeaveApplications(BuildContext context, mode,
{String? status, String? dateRange, DateTimeRange? customRange}) async { {String? status, String? dateRange, DateTimeRange? customRange}) async {
_isLoading = true; _isLoading = true;
_errorMessage = null; _errorMessage = null;
...@@ -83,6 +83,7 @@ class LeaveApplicationListProvider extends ChangeNotifier { ...@@ -83,6 +83,7 @@ class LeaveApplicationListProvider extends ChangeNotifier {
provider.empId, provider.empId,
dateParams['from']!, dateParams['from']!,
dateParams['to']!, dateParams['to']!,
mode
); );
debugPrint( debugPrint(
...@@ -253,9 +254,9 @@ class LeaveApplicationListProvider extends ChangeNotifier { ...@@ -253,9 +254,9 @@ class LeaveApplicationListProvider extends ChangeNotifier {
} }
/// Show Cupertino DatePicker for leave form /// Show Cupertino DatePicker for leave form
void showDatePickerDialog(BuildContext context, void showDatePickerDialog(BuildContext context, {bool isFromDate = true}) {
{bool isFromDate = true}) { DateTime now = DateTime.now();
DateTime? currentDate = DateTime.now(); DateTime? currentDate = now;
showCupertinoModalPopup<void>( showCupertinoModalPopup<void>(
context: context, context: context,
...@@ -286,10 +287,10 @@ class LeaveApplicationListProvider extends ChangeNotifier { ...@@ -286,10 +287,10 @@ class LeaveApplicationListProvider extends ChangeNotifier {
onPressed: () { onPressed: () {
if (isFromDate) { if (isFromDate) {
fromDateField.text = fromDateField.text =
_formatDate(currentDate ?? DateTime.now()); _formatDate(currentDate ?? now);
} else { } else {
toDateField.text = toDateField.text =
_formatDate(currentDate ?? DateTime.now()); _formatDate(currentDate ?? now);
} }
Navigator.pop(context); Navigator.pop(context);
}, },
...@@ -300,7 +301,9 @@ class LeaveApplicationListProvider extends ChangeNotifier { ...@@ -300,7 +301,9 @@ class LeaveApplicationListProvider extends ChangeNotifier {
Expanded( Expanded(
child: CupertinoDatePicker( child: CupertinoDatePicker(
dateOrder: DatePickerDateOrder.dmy, dateOrder: DatePickerDateOrder.dmy,
initialDateTime: currentDate, initialDateTime: now,
minimumDate: DateTime(now.year, now.month, now.day),
maximumDate: DateTime(now.year + 5), // limit
mode: CupertinoDatePickerMode.date, mode: CupertinoDatePickerMode.date,
onDateTimeChanged: (DateTime newDate) { onDateTimeChanged: (DateTime newDate) {
currentDate = newDate; currentDate = newDate;
...@@ -315,9 +318,10 @@ class LeaveApplicationListProvider extends ChangeNotifier { ...@@ -315,9 +318,10 @@ class LeaveApplicationListProvider extends ChangeNotifier {
} }
/// Apply filters /// Apply filters
void applyFilters(BuildContext context) { void applyFilters(BuildContext context,mode) {
fetchLeaveApplications( fetchLeaveApplications(
context, context,
mode,
status: _selectedStatus, status: _selectedStatus,
dateRange: _selectedDateRange, dateRange: _selectedDateRange,
customRange: _customDateRange, customRange: _customDateRange,
......
...@@ -227,6 +227,7 @@ class MyApp extends StatelessWidget { ...@@ -227,6 +227,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => followUpUpdateProvider()), ChangeNotifierProvider(create: (_) => followUpUpdateProvider()),
ChangeNotifierProvider(create: (_) => Appointmentcalendarprovider()), ChangeNotifierProvider(create: (_) => Appointmentcalendarprovider()),
ChangeNotifierProvider(create: (_) => Addnewleadsandprospectsprovider()), ChangeNotifierProvider(create: (_) => Addnewleadsandprospectsprovider()),
ChangeNotifierProvider(create: (_) => HrmAccessiblePagesProvider()),
ChangeNotifierProvider(create: (_) => Attendancelistprovider()), ChangeNotifierProvider(create: (_) => Attendancelistprovider()),
ChangeNotifierProvider(create: (_) => AttendanceDetailsProvider()), ChangeNotifierProvider(create: (_) => AttendanceDetailsProvider()),
ChangeNotifierProvider(create: (_) => TourExpensesProvider()), ChangeNotifierProvider(create: (_) => TourExpensesProvider()),
......
import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:intl/intl.dart';
import '../Utils/app_colors.dart'; import '../Utils/app_colors.dart';
import '../Utils/dropdownTheme.dart'; import '../Utils/dropdownTheme.dart';
...@@ -351,27 +352,30 @@ class CommonFilter2 { ...@@ -351,27 +352,30 @@ class CommonFilter2 {
], ],
), ),
), ),
if (tempSelectedValue == 'Custom') ...[
const SizedBox(height: 16),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey[300]!),
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.all(12),
child: buildCalendar(setState),
),
if (tempSelectedDateRange != null)
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Text(
'Selected: ${formatDate(tempSelectedDateRange!.start)} to ${formatDate(tempSelectedDateRange!.end)}',
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
),
),
],
const SizedBox(height: 20),
if (tempSelectedValue == 'Custom') ...[
const SizedBox(height: 16),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey[300]!),
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.all(12),
child: buildCalendar(setState),
),
if (tempSelectedDateRange != null)
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Text(
'Selected: ${DateFormat("dd MMM yyyy").format(tempSelectedDateRange!.start)} to ${DateFormat("dd MMM yyyy").format(tempSelectedDateRange!.end)}',
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
),
),
],
const SizedBox(height: 20),
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
......
...@@ -1863,21 +1863,43 @@ class _MyHomePageState extends State<MyHomePage> { ...@@ -1863,21 +1863,43 @@ class _MyHomePageState extends State<MyHomePage> {
profile.employeeeID, profile.employeeeID,
profile.mobileNUmber, profile.mobileNUmber,
]; ];
final itemText = textHeadings[index]?.toString() ?? "-";
return SizedBox( return SizedBox(
height: 40, height: 40,
child: Align( child: Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: InkWell(
"${textHeadings[index].toString()}", onTap: () {
textAlign: TextAlign.left, showJobDescriptionSheet(context, [
style: TextStyle( "Statewise End to end sales activities reg booking and dispatches and payment collection and branch visit every month & quarterly basis.",
fontSize: 14, "Conducting monthly/Quarterly/Annually– sales meeting, review of targets and achievements of total team.",
color: AppColors.semi_black, "Team CRM Tracking, Order Update Track and as well as payment entry in CRM by Team.",
"If required special Price to be taken from Prasad, Madhavi Madam/MD Sir.",
"Preparation of MIS reports on monthly basis (Rating wise data, employee wise data, TIV etc.).",
"Dispatch co-ordination with factory team- Anuradha / Sai Ram (commercial clearance with Susmitha / Rajeevi).",
"Commercial / Technical Support to BDE team order finalisation. If required client visit.",
"Team tour bills approvals in CRM.",
"Level -1 approvals to be given to sales team orders.",
"Outstanding payment collection followed on regular basis.",
]);
},
// no click for others
child: Text(
itemText,
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 14,
color: index == 2 ? AppColors.semi_black : AppColors.semi_black, // highlight clickable
decoration: index == 2 ? TextDecoration.underline : null,
),
), ),
), ),
), ),
); );
}, },
), ),
), ),
], ],
...@@ -1943,6 +1965,116 @@ class _MyHomePageState extends State<MyHomePage> { ...@@ -1943,6 +1965,116 @@ class _MyHomePageState extends State<MyHomePage> {
); );
} }
Future<void> showJobDescriptionSheet(
BuildContext context,
List<String> jobPoints,
) {
return showModalBottomSheet(
useSafeArea: true,
isDismissible: true,
isScrollControlled: true,
showDragHandle: true,
enableDrag: true,
backgroundColor: Colors.white,
context: context,
builder: (context) {
return SafeArea(
child: Container(
margin: const EdgeInsets.only(
bottom: 15,
left: 15,
right: 15,
top: 30,
),
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
/// Heading
Text(
"Job Description",
style: TextStyle(
fontFamily: "JakartaMedium",
fontSize: 16,
color: AppColors.app_blue, // same as Logout "Yes, Logout" button
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 15),
/// Bullet points list
...jobPoints.map(
(point) => Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"• ",
style: TextStyle(
fontSize: 14,
color: AppColors.semi_black,
),
),
Expanded(
child: Text(
point,
style: TextStyle(
fontSize: 14,
color: AppColors.semi_black,
fontFamily: "JakartaRegular",
height: 1.4, // line spacing
),
),
),
],
),
),
),
const SizedBox(height: 20),
/// Close button
InkWell(
onTap: () => Navigator.pop(context),
child: Container(
alignment: Alignment.center,
height: 45,
margin: const EdgeInsets.symmetric(
horizontal: 5.0,
vertical: 5.0,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
),
child: Center(
child: Text(
"Close",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.app_blue,
fontFamily: "JakartaMedium",
fontSize: 15,
),
),
),
),
),
],
),
),
),
);
},
);
}
Future<void> _showLogoutBottomSheet(BuildContext context) { Future<void> _showLogoutBottomSheet(BuildContext context) {
return showModalBottomSheet( return showModalBottomSheet(
useSafeArea: true, useSafeArea: true,
......
...@@ -125,187 +125,190 @@ class _AddLeaveRequestState extends State<AddLeaveRequest> { ...@@ -125,187 +125,190 @@ class _AddLeaveRequestState extends State<AddLeaveRequest> {
} }
Widget _scaffold(BuildContext context, LeaveApplicationListProvider provider) { Widget _scaffold(BuildContext context, LeaveApplicationListProvider provider) {
return Scaffold( return SafeArea(
resizeToAvoidBottomInset: true, top: false,
backgroundColor: AppColors.scaffold_bg_color, child: Scaffold(
appBar: appbarNew(context, widget.pageTitleName, 0xFFFFFFFF), resizeToAvoidBottomInset: true,
body: SingleChildScrollView( backgroundColor: AppColors.scaffold_bg_color,
child: Container( appBar: appbarNew(context, widget.pageTitleName, 0xFFFFFFFF),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), body: SingleChildScrollView(
margin: const EdgeInsets.all(12), child: Container(
decoration: BoxDecoration( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
color: AppColors.white, margin: const EdgeInsets.all(12),
borderRadius: BorderRadius.circular(20), decoration: BoxDecoration(
), color: AppColors.white,
child: Column( borderRadius: BorderRadius.circular(20),
crossAxisAlignment: CrossAxisAlignment.start, ),
children: [ child: Column(
/// From Date crossAxisAlignment: CrossAxisAlignment.start,
TextWidget(context, "From Date"), children: [
GestureDetector( /// From Date
onTap: () { TextWidget(context, "From Date"),
provider.showDatePickerDialog(context, isFromDate: true); GestureDetector(
if (fromDateError != null) { onTap: () {
setState(() => fromDateError = null); provider.showDatePickerDialog(context, isFromDate: true);
} if (fromDateError != null) {
}, setState(() => fromDateError = null);
child: textFieldNew(context, provider.fromDateField,
"Select Date", enabled: false),
),
errorWidget(context, fromDateError),
/// From Time
TextWidget(context, "From Time"),
GestureDetector(
onTap: () async {
TimeOfDay? picked = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
);
if (picked != null) {
provider.fromTimeField.text = picked.format(context);
if (fromTimeError != null) {
setState(() => fromTimeError = null);
} }
} },
}, child: textFieldNew(context, provider.fromDateField,
child: textFieldNew(context, provider.fromTimeField, "Select Date", enabled: false),
"Select Time", enabled: false), ),
), errorWidget(context, fromDateError),
errorWidget(context, fromTimeError),
/// To Date /// From Time
TextWidget(context, "To Date"), TextWidget(context, "From Time"),
GestureDetector( GestureDetector(
onTap: () { onTap: () async {
provider.showDatePickerDialog(context, isFromDate: false); TimeOfDay? picked = await showTimePicker(
if (toDateError != null) { context: context,
setState(() => toDateError = null); initialTime: TimeOfDay.now(),
} );
}, if (picked != null) {
child: textFieldNew(context, provider.toDateField, "Select Date", provider.fromTimeField.text = picked.format(context);
enabled: false), if (fromTimeError != null) {
), setState(() => fromTimeError = null);
errorWidget(context, toDateError), }
}
},
child: textFieldNew(context, provider.fromTimeField,
"Select Time", enabled: false),
),
errorWidget(context, fromTimeError),
/// To Time /// To Date
TextWidget(context, "To Time"), TextWidget(context, "To Date"),
GestureDetector( GestureDetector(
onTap: () async { onTap: () {
TimeOfDay? picked = await showTimePicker( provider.showDatePickerDialog(context, isFromDate: false);
context: context, if (toDateError != null) {
initialTime: TimeOfDay.now(), setState(() => toDateError = null);
);
if (picked != null) {
provider.toTimeField.text = picked.format(context);
if (toTimeError != null) {
setState(() => toTimeError = null);
} }
} },
}, child: textFieldNew(context, provider.toDateField, "Select Date",
child: textFieldNew(context, provider.toTimeField, "Select Time", enabled: false),
enabled: false), ),
), errorWidget(context, toDateError),
errorWidget(context, toTimeError),
/// Leave Type /// To Time
TextWidget(context, "Leave Type"), TextWidget(context, "To Time"),
Container( GestureDetector(
margin: const EdgeInsets.only(bottom: 6), onTap: () async {
padding: const EdgeInsets.symmetric(horizontal: 12), TimeOfDay? picked = await showTimePicker(
decoration: BoxDecoration( context: context,
color: AppColors.text_field_color, initialTime: TimeOfDay.now(),
borderRadius: BorderRadius.circular(14), );
if (picked != null) {
provider.toTimeField.text = picked.format(context);
if (toTimeError != null) {
setState(() => toTimeError = null);
}
}
},
child: textFieldNew(context, provider.toTimeField, "Select Time",
enabled: false),
), ),
child: DropdownButtonHideUnderline( errorWidget(context, toTimeError),
child: DropdownButton<String>(
isExpanded: true, /// Leave Type
hint: const Text("Select Leave Type", TextWidget(context, "Leave Type"),
style: TextStyle(fontSize: 14, color: Colors.grey)), Container(
value: leaveType, margin: const EdgeInsets.only(bottom: 6),
items: leaveTypes padding: const EdgeInsets.symmetric(horizontal: 12),
.map((e) => decoration: BoxDecoration(
DropdownMenuItem(value: e, child: Text(e))) color: AppColors.text_field_color,
.toList(), borderRadius: BorderRadius.circular(14),
onChanged: (val) { ),
setState(() { child: DropdownButtonHideUnderline(
leaveType = val; child: DropdownButton<String>(
if (leaveTypeError != null) { isExpanded: true,
leaveTypeError = null; hint: const Text("Select Leave Type",
} style: TextStyle(fontSize: 14, color: Colors.grey)),
}); value: leaveType,
}, items: leaveTypes
.map((e) =>
DropdownMenuItem(value: e, child: Text(e)))
.toList(),
onChanged: (val) {
setState(() {
leaveType = val;
if (leaveTypeError != null) {
leaveTypeError = null;
}
});
},
),
), ),
), ),
), errorWidget(context, leaveTypeError),
errorWidget(context, leaveTypeError),
/// Reason /// Reason
TextWidget(context, "Reason"), TextWidget(context, "Reason"),
textFieldNew(context, provider.reasonController, "Enter Reason", textFieldNew(context, provider.reasonController, "Enter Reason",
maxLines: 2), maxLines: 2),
errorWidget(context, reasonError), errorWidget(context, reasonError),
const SizedBox(height: 70), const SizedBox(height: 70),
], ],
),
), ),
), ),
), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, bottomNavigationBar: InkResponse(
bottomNavigationBar: InkResponse( onTap: () {
onTap: () { if (validateForm(provider)) {
if (validateForm(provider)) { provider.addLeaveRequest(
provider.addLeaveRequest( context,
context, fromDate: provider.fromDateField.text,
fromDate: provider.fromDateField.text, fromTime: provider.fromTimeField.text,
fromTime: provider.fromTimeField.text, toDate: provider.toDateField.text,
toDate: provider.toDateField.text, toTime: provider.toTimeField.text,
toTime: provider.toTimeField.text, leaveType: leaveType!,
leaveType: leaveType!, reason: provider.reasonController.text,
reason: provider.reasonController.text, );
);
// Reset after submit // Reset after submit
setState(() { setState(() {
provider.fromDateField.clear(); provider.fromDateField.clear();
provider.fromTimeField.clear(); provider.fromTimeField.clear();
provider.toDateField.clear(); provider.toDateField.clear();
provider.toTimeField.clear(); provider.toTimeField.clear();
provider.reasonController.clear(); provider.reasonController.clear();
leaveType = null; leaveType = null;
fromDateError = null; fromDateError = null;
fromTimeError = null; fromTimeError = null;
toDateError = null; toDateError = null;
toTimeError = null; toTimeError = null;
leaveTypeError = null; leaveTypeError = null;
reasonError = null; reasonError = null;
}); });
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar( const SnackBar(
content: Text("Leave request submitted successfully!"), content: Text("Leave request submitted successfully!"),
backgroundColor: Colors.black87, backgroundColor: Colors.black87,
), ),
); );
} }
}, },
child: Container( child: Container(
height: 45, height: 45,
alignment: Alignment.center, alignment: Alignment.center,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), margin: const EdgeInsets.symmetric(horizontal: 18, vertical: 10),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.app_blue, color: AppColors.app_blue,
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
), ),
child: provider.isSubmitting child: provider.isSubmitting
? const CircularProgressIndicator(color: Colors.white) ? const CircularProgressIndicator(color: Colors.white)
: const Text( : const Text(
"Submit", "Submit",
style: TextStyle( style: TextStyle(
fontSize: 15, fontSize: 15,
fontFamily: "JakartaMedium", fontFamily: "JakartaMedium",
color: Colors.white), color: Colors.white),
),
), ),
), ),
), ),
......