Commit 39774c76 authored by Sai Srinivas's avatar Sai Srinivas
Browse files

08-09-2025 Mohit Kumar

HRM Module Test Cases and UI
parent 1b1bfdfb
...@@ -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;
} }
} }
...@@ -15,7 +15,7 @@ class LeaveApplicationDetailsProvider extends ChangeNotifier { ...@@ -15,7 +15,7 @@ class LeaveApplicationDetailsProvider extends ChangeNotifier {
bool get isSubmitting => _isSubmitting; bool get isSubmitting => _isSubmitting;
CommonResponse? _StatusResponse; CommonResponse? _StatusResponse;
CommonResponse? get addResponse => _StatusResponse; CommonResponse? get Response => _StatusResponse;
leaveApplicationDetailsResponse? get response => _response; leaveApplicationDetailsResponse? get response => _response;
bool get isLoading => _isLoading; bool get isLoading => _isLoading;
......
...@@ -46,7 +46,7 @@ class AttendanceDetailsProvider extends ChangeNotifier { ...@@ -46,7 +46,7 @@ class AttendanceDetailsProvider extends ChangeNotifier {
_isLoading = false; _isLoading = false;
notifyListeners(); notifyListeners();
} }
Future<void> rejectAttendanceRequest( Future<void> rejectApproveAttendanceRequest(
BuildContext context, { BuildContext context, {
required String mode, required String mode,
required String type, required String type,
...@@ -60,8 +60,9 @@ class AttendanceDetailsProvider extends ChangeNotifier { ...@@ -60,8 +60,9 @@ class AttendanceDetailsProvider extends ChangeNotifier {
try { try {
final homeProvider = Provider.of<HomescreenNotifier>(context, listen: false); final homeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
print("############################+++++++++++++++++##########");
final result = await ApiCalling.attendanceRequestRejectAPI( final result = await ApiCalling.attendanceRequestApproveRejectAPI(
homeProvider.session, homeProvider.session,
homeProvider.empId, homeProvider.empId,
mode, mode,
......
...@@ -123,6 +123,8 @@ class Attendancelistprovider extends ChangeNotifier { ...@@ -123,6 +123,8 @@ 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
...@@ -231,6 +233,49 @@ class Attendancelistprovider extends ChangeNotifier { ...@@ -231,6 +233,49 @@ 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, mode,
......
...@@ -254,9 +254,9 @@ class LeaveApplicationListProvider extends ChangeNotifier { ...@@ -254,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,
...@@ -287,10 +287,10 @@ class LeaveApplicationListProvider extends ChangeNotifier { ...@@ -287,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);
}, },
...@@ -301,7 +301,9 @@ class LeaveApplicationListProvider extends ChangeNotifier { ...@@ -301,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;
......
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,6 +352,8 @@ class CommonFilter2 { ...@@ -351,6 +352,8 @@ class CommonFilter2 {
], ],
), ),
), ),
if (tempSelectedValue == 'Custom') ...[ if (tempSelectedValue == 'Custom') ...[
const SizedBox(height: 16), const SizedBox(height: 16),
Container( Container(
...@@ -365,12 +368,13 @@ class CommonFilter2 { ...@@ -365,12 +368,13 @@ class CommonFilter2 {
Padding( Padding(
padding: const EdgeInsets.only(top: 12.0), padding: const EdgeInsets.only(top: 12.0),
child: Text( child: Text(
'Selected: ${formatDate(tempSelectedDateRange!.start)} to ${formatDate(tempSelectedDateRange!.end)}', 'Selected: ${DateFormat("dd MMM yyyy").format(tempSelectedDateRange!.start)} to ${DateFormat("dd MMM yyyy").format(tempSelectedDateRange!.end)}',
style: TextStyle(fontSize: 14, color: Colors.grey[600]), style: TextStyle(fontSize: 14, color: Colors.grey[600]),
), ),
), ),
], ],
const SizedBox(height: 20), const SizedBox(height: 20),
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
......
...@@ -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: InkWell(
onTap: () {
showJobDescriptionSheet(context, [
"Statewise End to end sales activities reg booking and dispatches and payment collection and branch visit every month & quarterly basis.",
"Conducting monthly/Quarterly/Annually– sales meeting, review of targets and achievements of total team.",
"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( child: Text(
"${textHeadings[index].toString()}", itemText,
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
color: AppColors.semi_black, 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,7 +125,9 @@ class _AddLeaveRequestState extends State<AddLeaveRequest> { ...@@ -125,7 +125,9 @@ class _AddLeaveRequestState extends State<AddLeaveRequest> {
} }
Widget _scaffold(BuildContext context, LeaveApplicationListProvider provider) { Widget _scaffold(BuildContext context, LeaveApplicationListProvider provider) {
return Scaffold( return SafeArea(
top: false,
child: Scaffold(
resizeToAvoidBottomInset: true, resizeToAvoidBottomInset: true,
backgroundColor: AppColors.scaffold_bg_color, backgroundColor: AppColors.scaffold_bg_color,
appBar: appbarNew(context, widget.pageTitleName, 0xFFFFFFFF), appBar: appbarNew(context, widget.pageTitleName, 0xFFFFFFFF),
...@@ -292,8 +294,8 @@ class _AddLeaveRequestState extends State<AddLeaveRequest> { ...@@ -292,8 +294,8 @@ class _AddLeaveRequestState extends State<AddLeaveRequest> {
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),
...@@ -309,6 +311,7 @@ class _AddLeaveRequestState extends State<AddLeaveRequest> { ...@@ -309,6 +311,7 @@ class _AddLeaveRequestState extends State<AddLeaveRequest> {
), ),
), ),
), ),
),
); );
} }
......
...@@ -55,12 +55,36 @@ class _AddLiveAttendanceScreenState extends State<AddLiveAttendanceScreen> { ...@@ -55,12 +55,36 @@ class _AddLiveAttendanceScreenState extends State<AddLiveAttendanceScreen> {
} }
Future<void> _autoFetchLocation() async { Future<void> _autoFetchLocation() async {
String loc = await getCurrentLocation(); Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
// Save raw coordinates separately (for submission)
final coords = "${position.latitude},${position.longitude}";
// Convert to address for display
final placemarks =
await placemarkFromCoordinates(position.latitude, position.longitude);
String displayAddress;
if (placemarks.isNotEmpty) {
final place = placemarks.first;
displayAddress =
"${place.name}, ${place.locality}, ${place.administrativeArea}, ${place.country}";
} else {
displayAddress = coords; // fallback
}
setState(() { setState(() {
locationController.text = loc; locationController.text = displayAddress; // what user sees
_rawCoordinates = coords; // keep coords hidden for backend
}); });
} }
// Add this field at the top of your State class:
String? _rawCoordinates;
Future<String> getCurrentLocation() async { Future<String> getCurrentLocation() async {
try { try {
LocationPermission permission = await Geolocator.checkPermission(); LocationPermission permission = await Geolocator.checkPermission();
...@@ -164,7 +188,7 @@ class _AddLiveAttendanceScreenState extends State<AddLiveAttendanceScreen> { ...@@ -164,7 +188,7 @@ class _AddLiveAttendanceScreenState extends State<AddLiveAttendanceScreen> {
context, context,
process: "Live", process: "Live",
type: selectedType ?? "", type: selectedType ?? "",
loc: locationController.text, loc: _rawCoordinates ?? "", // send actual coordinates
checkDate: DateTime.now().toString().split(" ").first, checkDate: DateTime.now().toString().split(" ").first,
checkInTime: checkInTime:
selectedType == "Check In" ? TimeOfDay.now().format(context) : null, selectedType == "Check In" ? TimeOfDay.now().format(context) : null,
...@@ -198,7 +222,9 @@ class _AddLiveAttendanceScreenState extends State<AddLiveAttendanceScreen> { ...@@ -198,7 +222,9 @@ class _AddLiveAttendanceScreenState extends State<AddLiveAttendanceScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return SafeArea(
top: false,
child: Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
appBar: AppBar( appBar: AppBar(
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
...@@ -404,6 +430,7 @@ class _AddLiveAttendanceScreenState extends State<AddLiveAttendanceScreen> { ...@@ -404,6 +430,7 @@ class _AddLiveAttendanceScreenState extends State<AddLiveAttendanceScreen> {
], ],
), ),
), ),
),
); );
} }
......
...@@ -168,7 +168,7 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> { ...@@ -168,7 +168,7 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> {
} }
void _submitForm(BuildContext context) async { void _submitForm(BuildContext context) async {
// reset errors first // Reset errors first
dateError = null; dateError = null;
typeError = null; typeError = null;
checkInTimeError = checkInLocError = checkInDescError = checkInProofError = null; checkInTimeError = checkInLocError = checkInDescError = checkInProofError = null;
...@@ -176,15 +176,27 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> { ...@@ -176,15 +176,27 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> {
final provider = Provider.of<Attendancelistprovider>(context, listen: false); final provider = Provider.of<Attendancelistprovider>(context, listen: false);
// --- Date Validation --- // --- Date Validation (allow today, yesterday, day before yesterday) ---
if (provider.dateController.text.isEmpty) { if (provider.dateController.text.isEmpty) {
dateError = "Please select a date"; dateError = "Please select a date";
} else { } else {
try { try {
final enteredDate = DateFormat("dd MMM yyyy").parse(provider.dateController.text); final enteredDate = DateFormat("dd MMM yyyy").parse(provider.dateController.text);
provider.setSelectedDate(enteredDate); provider.setSelectedDate(enteredDate);
if (!provider.isDateValid()) {
dateError = "Date must be today or yesterday"; final today = DateTime.now();
final yesterday = today.subtract(const Duration(days: 1));
final dayBeforeYesterday = today.subtract(const Duration(days: 2));
// Normalize dates (ignore time part)
bool isValid = enteredDate.year == today.year &&
enteredDate.month == today.month &&
(enteredDate.day == today.day ||
enteredDate.day == yesterday.day ||
enteredDate.day == dayBeforeYesterday.day);
if (!isValid) {
dateError = "Date must be today, yesterday, or the day before yesterday";
} }
} catch (e) { } catch (e) {
dateError = "Invalid date format (use dd MMM yyyy)"; dateError = "Invalid date format (use dd MMM yyyy)";
...@@ -225,15 +237,15 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> { ...@@ -225,15 +237,15 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> {
checkOutDescError, checkOutDescError,
checkOutProofError checkOutProofError
].any((e) => e != null)) { ].any((e) => e != null)) {
setState(() {}); setState(() {}); // refresh UI to show error messages
return; return;
} }
// --- Format date for server (convert from "03 Sep 2025" to "2025-09-03" or whatever format server expects) --- // --- Format date for server ---
String formattedDate = ""; String formattedDate = "";
try { try {
final parsedDate = DateFormat("dd MMM yyyy").parse(provider.dateController.text); final parsedDate = DateFormat("dd MMM yyyy").parse(provider.dateController.text);
formattedDate = DateFormat("yyyy-MM-dd").format(parsedDate); // Change format as per server requirement formattedDate = DateFormat("yyyy-MM-dd").format(parsedDate);
} catch (e) { } catch (e) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Error formatting date: $e")), SnackBar(content: Text("Error formatting date: $e")),
...@@ -280,7 +292,7 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> { ...@@ -280,7 +292,7 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> {
: selectedType == "Check Out" : selectedType == "Check Out"
? checkOutLocation.text ? checkOutLocation.text
: "${checkInLocation.text}, ${checkOutLocation.text}", : "${checkInLocation.text}, ${checkOutLocation.text}",
checkDate: formattedDate, // Use the formatted date here checkDate: formattedDate,
checkInTime: finalCheckInTime, checkInTime: finalCheckInTime,
checkInLoc: finalCheckInLoc, checkInLoc: finalCheckInLoc,
checkInProof: finalCheckInProof, checkInProof: finalCheckInProof,
...@@ -290,14 +302,13 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> { ...@@ -290,14 +302,13 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> {
note: finalNote, note: finalNote,
); );
// Check the response from provider // --- Response handling ---
if (provider.addResponse != null && provider.addResponse!.error == "0") { if (provider.addResponse != null && provider.addResponse!.error == "0") {
// Success case
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(provider.addResponse!.message ?? "Attendance Submitted Successfully")), SnackBar(content: Text(provider.addResponse!.message ?? "Attendance Submitted Successfully")),
); );
// --- Reset fields --- // Reset fields
setState(() { setState(() {
selectedType = null; selectedType = null;
provider.dateController.clear(); provider.dateController.clear();
...@@ -313,19 +324,20 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> { ...@@ -313,19 +324,20 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> {
_fetchInitialLocation(); _fetchInitialLocation();
} else { } else {
// Error case - show appropriate message
String errorMessage = provider.errorMessage ?? "Failed to submit attendance"; String errorMessage = provider.errorMessage ?? "Failed to submit attendance";
// Handle specific server error for Check Out without Check In
if (errorMessage.contains("Check In is not Available")) { if (errorMessage.contains("Check In is not Available")) {
errorMessage = "Cannot submit Check Out without a Check In record for this date"; errorMessage = "Cannot submit Check Out without a Check In record for this date";
} }
if (errorMessage.contains("2")){
errorMessage = "Only One manual Request can be added in a month !";
}
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(errorMessage), backgroundColor: Colors.red), SnackBar(content: Text(errorMessage), backgroundColor: Colors.red),
); );
} }
} }
// it's date picker need to take day before yesterday, yesterday and today
......
...@@ -23,11 +23,15 @@ class AttendanceRequestDetailScreen extends StatefulWidget { ...@@ -23,11 +23,15 @@ class AttendanceRequestDetailScreen extends StatefulWidget {
class _AttendanceRequestDetailScreenState class _AttendanceRequestDetailScreenState
extends State<AttendanceRequestDetailScreen> { extends State<AttendanceRequestDetailScreen> {
bool _actionSubmitted = false;
late AttendanceDetailsProvider provider; late AttendanceDetailsProvider provider;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ChangeNotifierProvider( return SafeArea(
top: false,
child: ChangeNotifierProvider(
create: (_) => create: (_) =>
AttendanceDetailsProvider()..fetchAttendanceRequestDetail(context, widget.attendanceListId), AttendanceDetailsProvider()..fetchAttendanceRequestDetail(context, widget.attendanceListId),
child: Consumer<AttendanceDetailsProvider>( child: Consumer<AttendanceDetailsProvider>(
...@@ -78,9 +82,9 @@ class _AttendanceRequestDetailScreenState ...@@ -78,9 +82,9 @@ class _AttendanceRequestDetailScreenState
if (provider.isLoading) { if (provider.isLoading) {
return const Center(child: CircularProgressIndicator(color: Colors.blue,)); return const Center(child: CircularProgressIndicator(color: Colors.blue,));
} }
if (provider.errorMessage != null) { // if (provider.errorMessage != null) {
return Center(child: Text(provider.errorMessage!)); // return Center(child: Text(provider.errorMessage!));
} // }
if (provider.response?.requestDetails == null) { if (provider.response?.requestDetails == null) {
return const Center(child: Text("No details found")); return const Center(child: Text("No details found"));
} }
...@@ -96,7 +100,7 @@ class _AttendanceRequestDetailScreenState ...@@ -96,7 +100,7 @@ class _AttendanceRequestDetailScreenState
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16 * scaleFactor), borderRadius: BorderRadius.circular(16 * scaleFactor),
), ),
elevation: 2, elevation: 0,
child: Padding( child: Padding(
padding: EdgeInsets.all(16.0 * scaleFactor), padding: EdgeInsets.all(16.0 * scaleFactor),
child: Column( child: Column(
...@@ -104,7 +108,7 @@ class _AttendanceRequestDetailScreenState ...@@ -104,7 +108,7 @@ class _AttendanceRequestDetailScreenState
children: [ children: [
Container( Container(
margin: EdgeInsets.only(bottom: 0.5 * scaleFactor), margin: EdgeInsets.only(bottom: 0.5 * scaleFactor),
padding: EdgeInsets.all(12 * scaleFactor), padding: EdgeInsets.symmetric(horizontal: 2.5 * scaleFactor, vertical: 12 * scaleFactor),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(12 * scaleFactor), borderRadius: BorderRadius.circular(12 * scaleFactor),
...@@ -113,16 +117,16 @@ class _AttendanceRequestDetailScreenState ...@@ -113,16 +117,16 @@ class _AttendanceRequestDetailScreenState
children: [ children: [
/// Left Avatar /// Left Avatar
Container( Container(
height: 48 * scaleFactor, height: 44 * scaleFactor,
width: 48 * scaleFactor, width: 44 * scaleFactor,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: const Color(0xFFEDF8FF), // icon bg color: const Color(0xFFEDF8FF), // icon bg
), ),
child: Center( child: Center(
child: SvgPicture.asset( child: SvgPicture.asset(
height: 28 * scaleFactor, height: 24 * scaleFactor,
width: 28 * scaleFactor, width: 24 * scaleFactor,
"assets/svg/hrm/attendanceList.svg", "assets/svg/hrm/attendanceList.svg",
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
...@@ -239,12 +243,26 @@ class _AttendanceRequestDetailScreenState ...@@ -239,12 +243,26 @@ class _AttendanceRequestDetailScreenState
); );
}, },
), ),
bottomNavigationBar: widget.mode == "apr_lvl1" bottomNavigationBar: (widget.mode == "apr_lvl1"
&& !_actionSubmitted
&& provider.response?.requestDetails?.status != "Level 1 Approved"
&& provider.response?.requestDetails?.status != "Rejected")
? Container( ? Container(
decoration: const BoxDecoration(color: Colors.white), decoration: const BoxDecoration(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), gradient: LinearGradient(
height: 80, begin: Alignment.topCenter,
child: Row( end: Alignment.bottomCenter,
colors: [
Color(0xffFFFFFF),
Color(0x00FFFFFF),
],
),
),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
height: 61,
child: Column(
children: [
Row(
children: [ children: [
/// Reject Button /// Reject Button
Expanded( Expanded(
...@@ -254,7 +272,7 @@ class _AttendanceRequestDetailScreenState ...@@ -254,7 +272,7 @@ class _AttendanceRequestDetailScreenState
context: context, context: context,
actionType: "Reject", actionType: "Reject",
onSubmit: (remark) { onSubmit: (remark) {
provider.rejectAttendanceRequest( provider.rejectApproveAttendanceRequest(
context, context,
mode: widget.mode, mode: widget.mode,
type: "Rejected", type: "Rejected",
...@@ -262,14 +280,14 @@ class _AttendanceRequestDetailScreenState ...@@ -262,14 +280,14 @@ class _AttendanceRequestDetailScreenState
id: provider.response!.requestDetails!.id!, id: provider.response!.requestDetails!.id!,
); );
}, },
); ).then((_) {
provider.fetchAttendanceRequestDetail(context, widget.attendanceListId); // or setState(() {}) if needed
});
}, },
child: Container( child: Container(
alignment: Alignment.center, alignment: Alignment.center,
height: 45,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
color: const Color(0xFFFFFFFF),
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
...@@ -282,7 +300,13 @@ class _AttendanceRequestDetailScreenState ...@@ -282,7 +300,13 @@ class _AttendanceRequestDetailScreenState
), ),
), ),
), ),
const SizedBox(width: 10),
/// Vertical Divider
Container(
width: 1,
height: 45,
color: Colors.grey.shade300,
),
/// Approve Button /// Approve Button
Expanded( Expanded(
...@@ -291,8 +315,8 @@ class _AttendanceRequestDetailScreenState ...@@ -291,8 +315,8 @@ class _AttendanceRequestDetailScreenState
showRemarkSheet( showRemarkSheet(
context: context, context: context,
actionType: "Approve", actionType: "Approve",
onSubmit: (remark) { onSubmit: (remark) async {
provider.rejectAttendanceRequest( await provider.rejectApproveAttendanceRequest(
context, context,
mode: widget.mode, mode: widget.mode,
type: "Approved", type: "Approved",
...@@ -300,14 +324,15 @@ class _AttendanceRequestDetailScreenState ...@@ -300,14 +324,15 @@ class _AttendanceRequestDetailScreenState
id: provider.response!.requestDetails!.id!, id: provider.response!.requestDetails!.id!,
); );
}, },
); ).then((_) {
provider.fetchAttendanceRequestDetail(context, widget.attendanceListId); // or setState(() {}) if needed
});
}, },
child: Container( child: Container(
alignment: Alignment.center, alignment: Alignment.center,
height: 45,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
color: const Color(0xFFFFFFFF),
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
...@@ -322,12 +347,16 @@ class _AttendanceRequestDetailScreenState ...@@ -322,12 +347,16 @@ class _AttendanceRequestDetailScreenState
), ),
], ],
), ),
SizedBox(height: 0,)
],
),
) )
: const SizedBox.shrink(), : const SizedBox.shrink(),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
); );
}, },
) )
),
); );
} }
...@@ -411,7 +440,13 @@ class _AttendanceRequestDetailScreenState ...@@ -411,7 +440,13 @@ class _AttendanceRequestDetailScreenState
), ),
const SizedBox(height: 6), const SizedBox(height: 6),
TextField( Container(
margin: const EdgeInsets.only(bottom: 6),
decoration: BoxDecoration(
color: AppColors.text_field_color,
borderRadius: BorderRadius.circular(14),
),
child: TextField(
controller: remarkController, controller: remarkController,
maxLines: 3, maxLines: 3,
onChanged: (val) { onChanged: (val) {
...@@ -421,14 +456,12 @@ class _AttendanceRequestDetailScreenState ...@@ -421,14 +456,12 @@ class _AttendanceRequestDetailScreenState
}, },
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Enter your remark here...", hintText: "Enter your remark here...",
filled: true, hintStyle: TextStyle(
fillColor: Colors.grey.shade100, color: Colors.grey.shade500, // Customize this color
border: OutlineInputBorder( fontSize: 14, // Optional: tweak font size
borderRadius: BorderRadius.circular(12),
), ),
contentPadding: const EdgeInsets.symmetric( border: InputBorder.none,
vertical: 12, contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
horizontal: 12,
), ),
), ),
), ),
...@@ -444,7 +477,7 @@ class _AttendanceRequestDetailScreenState ...@@ -444,7 +477,7 @@ class _AttendanceRequestDetailScreenState
child: Container( child: Container(
height: 45, height: 45,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.red.shade100, color: Color(0x12AAAAAA),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: const Center( child: const Center(
...@@ -478,7 +511,6 @@ class _AttendanceRequestDetailScreenState ...@@ -478,7 +511,6 @@ class _AttendanceRequestDetailScreenState
); );
} }
}, },
child: Container( child: Container(
height: 45, height: 45,
decoration: BoxDecoration( decoration: BoxDecoration(
...@@ -553,20 +585,23 @@ class _AttendanceRequestDetailScreenState ...@@ -553,20 +585,23 @@ class _AttendanceRequestDetailScreenState
/// for location /// for location
/// Location Tile
Widget buildLocationTile(String label, String? value, double scaleFactor) { Widget buildLocationTile(String label, String? value, double scaleFactor) {
return FutureBuilder<String>( return FutureBuilder<String>(
future: getReadableLocation(value), future: getReadableLocation(value),
builder: (context, snapshot) { builder: (context, snapshot) {
final locationText = snapshot.data ?? "-"; final locationText = snapshot.connectionState == ConnectionState.done
? (snapshot.data ?? value ?? "-")
: value ?? "-";
return Padding( return Padding(
padding: EdgeInsets.symmetric(vertical: 6 * scaleFactor), padding: EdgeInsets.symmetric(vertical: 6 * scaleFactor),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, // aligns top when wrapping crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Label // Label
Expanded( Expanded(
flex: 5, // ratio (adjust same as your Date/Time tile) flex: 5,
child: Text( child: Text(
label, label,
style: TextStyle( style: TextStyle(
...@@ -579,14 +614,13 @@ class _AttendanceRequestDetailScreenState ...@@ -579,14 +614,13 @@ class _AttendanceRequestDetailScreenState
// Value (Clickable Location) // Value (Clickable Location)
Expanded( Expanded(
flex: 5, // take remaining space flex: 5,
child: GestureDetector( child: GestureDetector(
onTap: () async { onTap: () async {
final uri = Uri.parse( final uri = Uri.parse(
"https://www.google.com/maps/search/?api=1&query=$value"); "https://www.google.com/maps/search/?api=1&query=$value");
if (await canLaunchUrl(uri)) { if (await canLaunchUrl(uri)) {
await launchUrl(uri, await launchUrl(uri, mode: LaunchMode.externalApplication);
mode: LaunchMode.externalApplication);
} }
}, },
child: Text( child: Text(
...@@ -609,20 +643,40 @@ class _AttendanceRequestDetailScreenState ...@@ -609,20 +643,40 @@ class _AttendanceRequestDetailScreenState
); );
} }
/// Convert coordinates -> human readable location
/// Convert coordinates -> full human readable location
Future<String> getReadableLocation(String? value) async { Future<String> getReadableLocation(String? value) async {
if (value == null) return "-"; if (value == null || value.isEmpty) return "-";
try { try {
List<Location> locations = await locationFromAddress(value); // Expecting "lat,lng"
List<Placemark> placemarks = await placemarkFromCoordinates( final parts = value.split(',');
locations[0].latitude, if (parts.length != 2) return value;
locations[0].longitude,
); final lat = double.tryParse(parts[0].trim());
return placemarks.first.locality ?? value; final lng = double.tryParse(parts[1].trim());
if (lat == null || lng == null) return value;
final placemarks = await placemarkFromCoordinates(lat, lng);
final place = placemarks.first;
// Include more details
final address = [
place.name,
place.street, // e.g. "A-46, Lata Enclave"
place.subLocality, // e.g. "Madhura Nagar"
place.locality, // e.g. "Hyderabad"
place.administrativeArea, // e.g. "Telangana"
place.postalCode, // e.g. "500038"
place.country // e.g. "India"
].where((e) => e != null && e.isNotEmpty).join(", ");
return address;
} catch (e) { } catch (e) {
return value; // fallback to raw coordinates return value; // fallback to raw coordinates
} }
} }
/// for date and time /// for date and time
Widget _buildDate_TimeTile(String label, String? date, String? time, double scaleFactor) { Widget _buildDate_TimeTile(String label, String? date, String? time, double scaleFactor) {
return Padding( return Padding(
...@@ -718,8 +772,16 @@ class _AttendanceRequestDetailScreenState ...@@ -718,8 +772,16 @@ class _AttendanceRequestDetailScreenState
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: builder:
(context) => Image.network(filePath), (
// Fileviewer(fileName: label, fileUrl: "assets/images/capa.svg"), context,
) => Fileviewer(
fileName:
filePath ??
"",
fileUrl:
filePath ??
"",
),
), ),
); );
}, },
......
This diff is collapsed.
...@@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; ...@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:generp/screens/hrm/Attendancelist.dart'; import 'package:generp/screens/hrm/Attendancelist.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../Utils/app_colors.dart'; import '../../Utils/app_colors.dart';
import 'AttendanceRequestDetail.dart'; import 'AttendanceRequestDetail.dart';
import 'LeaveApplicationScreen.dart'; import 'LeaveApplicationScreen.dart';
...@@ -39,7 +38,9 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> { ...@@ -39,7 +38,9 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return SafeArea(
top: false,
child: Scaffold(
appBar: AppBar( appBar: AppBar(
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
backgroundColor: const Color(0xFFCEEDFF), backgroundColor: const Color(0xFFCEEDFF),
...@@ -221,6 +222,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> { ...@@ -221,6 +222,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
], ],
), ),
), ),
),
); );
} }
...@@ -287,8 +289,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> { ...@@ -287,8 +289,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
Expanded( Expanded(
flex: 1, flex: 1,
child: Container( child: Container(
height: constraints.maxHeight * 0.5, // Responsive size height: constraints.maxHeight * 0.39,
width: constraints.maxHeight * 0.5, // Responsive size width: constraints.maxHeight * 0.39,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: const Color(0xFFEDF8FF), color: const Color(0xFFEDF8FF),
...@@ -296,8 +298,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> { ...@@ -296,8 +298,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
child: Center( child: Center(
child: SvgPicture.asset( child: SvgPicture.asset(
assetIcon, assetIcon,
height: constraints.maxHeight * 0.3, // Responsive size height: constraints.maxHeight * 0.19,
width: constraints.maxHeight * 0.3, // Responsive size width: constraints.maxHeight * 0.19,
), ),
), ),
), ),
......
...@@ -31,7 +31,9 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen> ...@@ -31,7 +31,9 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ChangeNotifierProvider( return SafeArea(
top: false,
child: ChangeNotifierProvider(
create: (_) { create: (_) {
final provider = LeaveApplicationListProvider(); final provider = LeaveApplicationListProvider();
Future.microtask(() { Future.microtask(() {
...@@ -120,7 +122,7 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen> ...@@ -120,7 +122,7 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen>
final list = provider.response!.requestList!; final list = provider.response!.requestList!;
return ListView.builder( return ListView.builder(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 10),
itemCount: list.length, itemCount: list.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = list[index]; final item = list[index];
...@@ -152,7 +154,7 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen> ...@@ -152,7 +154,7 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen>
margin: const EdgeInsets.symmetric(horizontal: 8.5, vertical: 5), margin: const EdgeInsets.symmetric(horizontal: 8.5, vertical: 5),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,//Color(int.parse(item.rowColor!.replaceFirst('#', '0xff'))),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
), ),
child: Row( child: Row(
...@@ -185,7 +187,9 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen> ...@@ -185,7 +187,9 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen>
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
item.leaveType ?? "-", widget.mode == "teamleader"
? item.employeeName ?? "-"
: item.leaveType ?? "-",
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
...@@ -228,22 +232,23 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen> ...@@ -228,22 +232,23 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen>
), ),
), ),
// /// Right Status /// Right Status
// Container( if (widget.mode == "teamleader")
// padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), Container(
// decoration: BoxDecoration( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
// color: _getStatusBackgroundColor(item.status), decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(10), color: Color(0x00FFFFFF),
// ), borderRadius: BorderRadius.circular(10),
// child: Text( ),
// item.status ?? "-", child: Text(
// style: TextStyle( item.leaveType ?? "-",
// fontFamily: "JakartaMedium", style: TextStyle(
// fontSize: 13, fontFamily: "JakartaMedium",
// color: _getStatusTextColor(item.status), fontSize: 13,
// ), color: AppColors.app_blue,
// ), ),
// ), ),
),
], ],
), ),
), ),
...@@ -252,13 +257,17 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen> ...@@ -252,13 +257,17 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen>
); );
}, },
), ),
) ),
SizedBox(height: 28,)
], ],
), ),
floatingActionButtonLocation: bottomNavigationBar: widget.mode == "teamleader"
FloatingActionButtonLocation.centerFloat, ? null
floatingActionButton: InkResponse( : Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
color: Colors.white,
child: InkResponse(
onTap: () { onTap: () {
HapticFeedback.selectionClick(); HapticFeedback.selectionClick();
Navigator.push( Navigator.push(
...@@ -278,8 +287,8 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen> ...@@ -278,8 +287,8 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen>
child: Container( child: Container(
height: 45, height: 45,
alignment: Alignment.center, alignment: Alignment.center,
margin: EdgeInsets.symmetric(horizontal: 20), margin: EdgeInsets.symmetric(horizontal: 14),
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), padding: EdgeInsets.symmetric(horizontal: 6, vertical: 5),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.app_blue, color: AppColors.app_blue,
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
...@@ -294,15 +303,20 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen> ...@@ -294,15 +303,20 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen>
), ),
), ),
), ),
),
); );
}, },
); );
}, },
),
); );
} }
/// Get status background color /// Get status background color
Color _getStatusBackgroundColor(String? status) { Color _getStatusBackgroundColor(String? status) {
switch (status?.toLowerCase()) { switch (status?.toLowerCase()) {
...@@ -316,13 +330,14 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen> ...@@ -316,13 +330,14 @@ class _LeaveApplicationListScreenState extends State<LeaveApplicationListScreen>
} }
} }
/// Get status text color /// Get status text color
Color _getStatusTextColor(String? status) { Color _getStatusTextColor(String? status) {
switch (status?.toLowerCase()) { switch (status?.toLowerCase()) {
case 'approved': case 'approved':
return AppColors.approved_text_color; return AppColors.approved_text_color;
case 'rejected': case 'rejected':
return AppColors.rejected_text_color; return Colors.redAccent.shade200;
case 'requested': case 'requested':
default: default:
return AppColors.requested_text_color; return AppColors.requested_text_color;
......
...@@ -17,7 +17,9 @@ class RewardListScreen extends StatefulWidget { ...@@ -17,7 +17,9 @@ class RewardListScreen extends StatefulWidget {
class _RewardListScreenState extends State<RewardListScreen> { class _RewardListScreenState extends State<RewardListScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ChangeNotifierProvider( return SafeArea(
top: false,
child: ChangeNotifierProvider(
create: (_) => create: (_) =>
RewardListProvider()..fetchRewardList(context), RewardListProvider()..fetchRewardList(context),
child: Consumer<RewardListProvider>( child: Consumer<RewardListProvider>(
...@@ -296,6 +298,7 @@ class _RewardListScreenState extends State<RewardListScreen> { ...@@ -296,6 +298,7 @@ class _RewardListScreenState extends State<RewardListScreen> {
); );
} }
) )
),
); );
} }
...@@ -315,13 +318,13 @@ class _RewardListScreenState extends State<RewardListScreen> { ...@@ -315,13 +318,13 @@ class _RewardListScreenState extends State<RewardListScreen> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
boxShadow: [ // boxShadow: [
BoxShadow( // BoxShadow(
color: Colors.grey.withOpacity(0.1), // color: Colors.grey.withOpacity(0.1),
blurRadius: 6, // blurRadius: 6,
offset: const Offset(0, 3), // offset: const Offset(0, 3),
) // )
], // ],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
......
...@@ -19,7 +19,9 @@ class TourExpensesDetailsScreen extends StatefulWidget { ...@@ -19,7 +19,9 @@ class TourExpensesDetailsScreen extends StatefulWidget {
class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ChangeNotifierProvider( return SafeArea(
top: false,
child: ChangeNotifierProvider(
create: (_) => TourExpensesDetailsProvider() create: (_) => TourExpensesDetailsProvider()
..fetchTourExpensesDetails(context, widget.tourBillId), ..fetchTourExpensesDetails(context, widget.tourBillId),
child: Scaffold( child: Scaffold(
...@@ -179,8 +181,16 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{ ...@@ -179,8 +181,16 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: builder:
(context) => Image.network(t.imageDirFilePath.toString()), (
// Fileviewer(fileName: label, fileUrl: "assets/images/capa.svg"), context,
) => Fileviewer(
fileName:
t.imageDirFilePath ??
"",
fileUrl:
t.imageDirFilePath ??
"",
),
), ),
); );
}, },
...@@ -228,16 +238,19 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{ ...@@ -228,16 +238,19 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{
toDate: h.toDate ?? "-", toDate: h.toDate ?? "-",
onViewTap: () { onViewTap: () {
debugPrint("Open: ${h.imageDirFilePath}"); debugPrint("Open: ${h.imageDirFilePath}");
showDialog( Navigator.push(
context: context, context,
builder: (_) => Dialog( MaterialPageRoute(
shape: RoundedRectangleBorder( builder:
borderRadius: BorderRadius.circular(12), (
), context,
child: ClipRRect( ) => Fileviewer(
borderRadius: BorderRadius.circular(12), fileName:
child: Image.network(h.imageDirFilePath.toString()) h.imageDirFilePath ??
"",
fileUrl:
h.imageDirFilePath ??
"",
), ),
), ),
); );
...@@ -285,16 +298,19 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{ ...@@ -285,16 +298,19 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{
date: o.otherDate ?? "-", date: o.otherDate ?? "-",
onViewTap: () { onViewTap: () {
debugPrint("Open: ${o.imageDirFilePath}"); debugPrint("Open: ${o.imageDirFilePath}");
showDialog( Navigator.push(
context: context, context,
builder: (_) => Dialog( MaterialPageRoute(
shape: RoundedRectangleBorder( builder:
borderRadius: BorderRadius.circular(12), (
), context,
child: ClipRRect( ) => Fileviewer(
borderRadius: BorderRadius.circular(12), fileName:
child: Image.network(o.imageDirFilePath.toString()) o.imageDirFilePath ??
"",
fileUrl:
o.imageDirFilePath ??
"",
), ),
), ),
); );
...@@ -314,6 +330,7 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{ ...@@ -314,6 +330,7 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{
}, },
), ),
), ),
),
); );
} }
...@@ -334,13 +351,13 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{ ...@@ -334,13 +351,13 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
boxShadow: [ // boxShadow: [
BoxShadow( // BoxShadow(
color: Colors.grey.withOpacity(0.1), // color: Colors.grey.withOpacity(0.1),
blurRadius: 6, // blurRadius: 6,
offset: const Offset(0, 3), // offset: const Offset(0, 3),
) // )
], // ],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
...@@ -407,13 +424,13 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{ ...@@ -407,13 +424,13 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
boxShadow: [ // boxShadow: [
BoxShadow( // BoxShadow(
color: Colors.grey.withOpacity(0.1), // color: Colors.grey.withOpacity(0.1),
blurRadius: 6, // blurRadius: 6,
offset: const Offset(0, 3), // offset: const Offset(0, 3),
) // )
], // ],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
...@@ -477,13 +494,13 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{ ...@@ -477,13 +494,13 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
boxShadow: [ // boxShadow: [
BoxShadow( // BoxShadow(
color: Colors.grey.withOpacity(0.1), // color: Colors.grey.withOpacity(0.1),
blurRadius: 6, // blurRadius: 6,
offset: const Offset(0, 3), // offset: const Offset(0, 3),
) // )
], // ],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
...@@ -548,13 +565,13 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{ ...@@ -548,13 +565,13 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
boxShadow: [ // boxShadow: [
BoxShadow( // BoxShadow(
color: Colors.grey.withOpacity(0.1), // color: Colors.grey.withOpacity(0.1),
blurRadius: 6, // blurRadius: 6,
offset: const Offset(0, 3), // offset: const Offset(0, 3),
) // )
], // ],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
...@@ -681,7 +698,7 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{ ...@@ -681,7 +698,7 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen>{
bottomRight: Radius.circular(30), bottomRight: Radius.circular(30),
), ),
), ),
elevation: 2, elevation: 0,
child: Container( child: Container(
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Colors.white, color: Colors.white,
......
...@@ -168,38 +168,36 @@ class _TourExpensesListScreenState extends State<TourExpensesListScreen> { ...@@ -168,38 +168,36 @@ class _TourExpensesListScreenState extends State<TourExpensesListScreen> {
], ],
), ),
floatingActionButtonLocation: bottomNavigationBar: Container(
FloatingActionButtonLocation.centerFloat, padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 10),
floatingActionButton: InkResponse( color: Colors.white,
onTap: () { child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xff1487c9), // App blue
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
padding: const EdgeInsets.symmetric(vertical: 14),
elevation: 0, // Optional: remove shadow
),
onPressed: () {
HapticFeedback.selectionClick(); HapticFeedback.selectionClick();
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => builder: (context) => const AddBillScreen(pageTitleName: "Add Bill"),
const AddBillScreen(pageTitleName: "Add Bill",), settings: const RouteSettings(name: 'AddTourExpBillScreen'),
settings: const RouteSettings(
name: 'AddTourExpBillScreen'),
), ),
).then((_) { ).then((_) {
provider.fetchTourExpenses(context, "1"); provider.fetchTourExpenses(context, "1");
}); });
// show add bill screen here
}, },
child: Container( child: const Text(
height: 45,
alignment: Alignment.center,
margin: EdgeInsets.symmetric(horizontal: 20),
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: AppColors.app_blue,
borderRadius: BorderRadius.circular(15),
),
child: Text(
"Add Bill", "Add Bill",
style: TextStyle( style: TextStyle(
fontSize: 15, fontSize: 16,
fontFamily: "JakartaMedium", fontFamily: "JakartaMedium",
fontWeight: FontWeight.w500,
color: Colors.white, color: Colors.white,
), ),
), ),
......
...@@ -5048,7 +5048,7 @@ class ApiCalling { ...@@ -5048,7 +5048,7 @@ class ApiCalling {
} }
} }
static Future<CommonResponse?> attendanceRequestRejectAPI( static Future<CommonResponse?> attendanceRequestApproveRejectAPI(
session, session,
empId, empId,
mode, mode,
...@@ -5067,7 +5067,7 @@ class ApiCalling { ...@@ -5067,7 +5067,7 @@ class ApiCalling {
}; };
final res = await post(data, AttendanceRequestRejectUrl, {}); final res = await post(data, AttendanceRequestRejectUrl, {});
if (res != null) { if (res != null) {
print(data); print("Attendance App Reje:${data}");
debugPrint(res.body); debugPrint(res.body);
return CommonResponse.fromJson(jsonDecode(res.body)); return CommonResponse.fromJson(jsonDecode(res.body));
} else { } else {
...@@ -5368,6 +5368,7 @@ class ApiCalling { ...@@ -5368,6 +5368,7 @@ class ApiCalling {
'requested_date_from': (dateFrom), 'requested_date_from': (dateFrom),
'requested_date_to': (dateTo), 'requested_date_to': (dateTo),
'mode': (mode), 'mode': (mode),
}; };
final res = await post(data, LeaveApplicationListUrl, {}); final res = await post(data, LeaveApplicationListUrl, {});
if (res != null) { if (res != null) {
...@@ -5463,7 +5464,7 @@ class ApiCalling { ...@@ -5463,7 +5464,7 @@ class ApiCalling {
'remarks': (remarks).toString(), 'remarks': (remarks).toString(),
'id': (id).toString(), 'id': (id).toString(),
}; };
final res = await post(data, AttendanceRequestRejectUrl, {}); final res = await post(data, LeaveRequestRejectAprroveUrl, {});
if (res != null) { if (res != null) {
print(data); print(data);
debugPrint(res.body); debugPrint(res.body);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment