chnages has been made
This commit is contained in:
@@ -22,7 +22,7 @@ class RequestLeaveScreen extends StatefulWidget {
|
||||
|
||||
class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
// Dropdown value - initialize with default
|
||||
String leaveType = "إجازة مرضية ";
|
||||
String leaveType = "إجازة مرضية";
|
||||
|
||||
// Toggle switch
|
||||
bool isTimedLeave = false;
|
||||
@@ -41,12 +41,133 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
final RequestService _requestService = RequestService();
|
||||
|
||||
// Use cases
|
||||
final CreateVacationUseCase _createVacationUseCase = sl<CreateVacationUseCase>();
|
||||
final GetVacationTypesUseCase _getVacationTypesUseCase = sl<GetVacationTypesUseCase>();
|
||||
final CreateVacationUseCase _createVacationUseCase =
|
||||
sl<CreateVacationUseCase>();
|
||||
final GetVacationTypesUseCase _getVacationTypesUseCase =
|
||||
sl<GetVacationTypesUseCase>();
|
||||
|
||||
// Vacation types from API
|
||||
List<VacationTypeModel> _vacationTypes = [];
|
||||
int? _selectedVacationTypeValue; // Store selected type value instead of string
|
||||
|
||||
// Store selected type value instead of string
|
||||
int? _selectedVacationTypeValue;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadVacationTypes();
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// STEP A: single helper for selecting type safely
|
||||
// -------------------------------
|
||||
void _setSelectedVacationType(int value) {
|
||||
_selectedVacationTypeValue = value;
|
||||
|
||||
if (_vacationTypes.isNotEmpty) {
|
||||
final selectedType = _vacationTypes.firstWhere(
|
||||
(t) => t.value == value,
|
||||
orElse: () => _vacationTypes.first,
|
||||
);
|
||||
leaveType = _getArabicName(selectedType.name);
|
||||
} else {
|
||||
// Fallback text (when API not loaded yet)
|
||||
if (value == 0) leaveType = "إجازة زمنية";
|
||||
if (value == 1) leaveType = "إجازة مرضية";
|
||||
if (value == 2) leaveType = "إجازة مدفوعة";
|
||||
if (value == 3) leaveType = "إجازة غير مدفوعة";
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// STEP B: single helper for timed leave rule
|
||||
// -------------------------------
|
||||
void _setTimedLeave(bool on) {
|
||||
setState(() {
|
||||
isTimedLeave = on;
|
||||
|
||||
if (isTimedLeave) {
|
||||
// FORCE TimeOff (value = 1)
|
||||
_setSelectedVacationType(0);
|
||||
|
||||
// Optional: keep dates consistent for timed leave (same day)
|
||||
toDate = fromDate;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadVacationTypes() async {
|
||||
final result = await _getVacationTypesUseCase();
|
||||
result.fold(
|
||||
(failure) {
|
||||
print('Failed to load vacation types: ${_getFailureMessage(failure)}');
|
||||
},
|
||||
(response) {
|
||||
if (!mounted) return;
|
||||
|
||||
setState(() {
|
||||
_vacationTypes = response.data;
|
||||
|
||||
if (_vacationTypes.isEmpty) return;
|
||||
|
||||
// IMPORTANT:
|
||||
// If toggle already ON -> force TimeOff
|
||||
if (isTimedLeave) {
|
||||
final timeOff = _vacationTypes.firstWhere(
|
||||
(t) => t.value == 1,
|
||||
orElse: () => _vacationTypes.first,
|
||||
);
|
||||
_setSelectedVacationType(timeOff.value);
|
||||
} else {
|
||||
// Otherwise default to SickLeave (2) if available
|
||||
final sickLeave = _vacationTypes.firstWhere(
|
||||
(type) => type.value == 2,
|
||||
orElse: () => _vacationTypes.first,
|
||||
);
|
||||
_setSelectedVacationType(sickLeave.value);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
String _getArabicName(String apiName) {
|
||||
switch (apiName) {
|
||||
case 'TimeOff':
|
||||
return 'إجازة زمنية';
|
||||
case 'SickLeave':
|
||||
return 'إجازة مرضية';
|
||||
case 'PaidLeave':
|
||||
return 'إجازة مدفوعة';
|
||||
case 'UnpaidLeave':
|
||||
return 'إجازة غير مدفوعة';
|
||||
default:
|
||||
return apiName;
|
||||
}
|
||||
}
|
||||
|
||||
int _getVacationTypeValue() {
|
||||
if (_selectedVacationTypeValue != null) {
|
||||
return _selectedVacationTypeValue!;
|
||||
}
|
||||
|
||||
if (leaveType.contains("مرضية") || leaveType == "SickLeave") {
|
||||
return 1;
|
||||
} else if (leaveType.contains("مدفوعة") && !leaveType.contains("غير")) {
|
||||
return 2;
|
||||
} else if (leaveType.contains("غير مدفوعة") || leaveType == "UnpaidLeave") {
|
||||
return 3;
|
||||
} else if (leaveType.contains("زمنية") || leaveType == "TimeOff") {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
String _getFailureMessage(Failure failure) {
|
||||
if (failure is ServerFailure) return failure.message;
|
||||
if (failure is NetworkFailure) return failure.message;
|
||||
return 'حدث خطأ غير متوقع';
|
||||
}
|
||||
|
||||
/// PICK DATE
|
||||
Future<void> pickDate(bool isFrom) async {
|
||||
@@ -56,15 +177,15 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
initialDate: initial,
|
||||
firstDate: DateTime(2020),
|
||||
lastDate: DateTime(2035),
|
||||
builder: (context, child) {
|
||||
return Theme(data: ThemeData.dark(), child: child!);
|
||||
},
|
||||
builder: (context, child) => Theme(data: ThemeData.dark(), child: child!),
|
||||
);
|
||||
|
||||
if (newDate != null) {
|
||||
setState(() {
|
||||
if (isFrom) {
|
||||
fromDate = newDate;
|
||||
// If timed leave, keep toDate same as fromDate
|
||||
if (isTimedLeave) toDate = newDate;
|
||||
} else {
|
||||
toDate = newDate;
|
||||
}
|
||||
@@ -78,9 +199,7 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
TimeOfDay? newTime = await showTimePicker(
|
||||
context: context,
|
||||
initialTime: initial,
|
||||
builder: (context, child) {
|
||||
return Theme(data: ThemeData.dark(), child: child!);
|
||||
},
|
||||
builder: (context, child) => Theme(data: ThemeData.dark(), child: child!),
|
||||
);
|
||||
|
||||
if (newTime != null) {
|
||||
@@ -94,85 +213,8 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadVacationTypes();
|
||||
}
|
||||
|
||||
Future<void> _loadVacationTypes() async {
|
||||
final result = await _getVacationTypesUseCase();
|
||||
result.fold(
|
||||
(failure) {
|
||||
// Silently fail - user can still submit with default types
|
||||
print('Failed to load vacation types: ${_getFailureMessage(failure)}');
|
||||
},
|
||||
(response) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_vacationTypes = response.data;
|
||||
// Set default to SickLeave (value: 2) if available
|
||||
if (_vacationTypes.isNotEmpty) {
|
||||
final sickLeave = _vacationTypes.firstWhere(
|
||||
(type) => type.value == 2,
|
||||
orElse: () => _vacationTypes.first,
|
||||
);
|
||||
_selectedVacationTypeValue = sickLeave.value;
|
||||
leaveType = _getArabicName(sickLeave.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
String _getArabicName(String apiName) {
|
||||
// Map API names to Arabic display names
|
||||
switch (apiName) {
|
||||
case 'TimeOff':
|
||||
return 'أجازة زمنية';
|
||||
case 'SickLeave':
|
||||
return 'إجازة مرضية';
|
||||
case 'PaidLeave':
|
||||
return 'إجازة مدفوعة';
|
||||
case 'UnpaidLeave':
|
||||
return 'إجازة غير مدفوعة';
|
||||
default:
|
||||
return apiName;
|
||||
}
|
||||
}
|
||||
|
||||
int _getVacationTypeValue() {
|
||||
// Use selected value if available, otherwise fallback to mapping
|
||||
if (_selectedVacationTypeValue != null) {
|
||||
return _selectedVacationTypeValue!;
|
||||
}
|
||||
// Fallback: Map display names to API type values
|
||||
if (leaveType.contains("مرضية") || leaveType == "SickLeave") {
|
||||
return 2; // SickLeave
|
||||
} else if (leaveType.contains("مدفوعة") && !leaveType.contains("غير")) {
|
||||
return 3; // PaidLeave
|
||||
} else if (leaveType.contains("غير مدفوعة") || leaveType == "UnpaidLeave") {
|
||||
return 4; // UnpaidLeave
|
||||
} else if (leaveType.contains("زمنية") || leaveType == "TimeOff") {
|
||||
return 1; // TimeOff
|
||||
}
|
||||
return 1; // Default to TimeOff
|
||||
}
|
||||
|
||||
String _getFailureMessage(Failure failure) {
|
||||
if (failure is ServerFailure) {
|
||||
return failure.message;
|
||||
} else if (failure is NetworkFailure) {
|
||||
return failure.message;
|
||||
}
|
||||
return 'حدث خطأ غير متوقع';
|
||||
}
|
||||
|
||||
// Method to save the leave request
|
||||
Future<void> _saveLeaveRequest() async {
|
||||
if (reasonController.text.isEmpty) {
|
||||
// Show an error message if reason is empty
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
@@ -184,7 +226,6 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get employee ID
|
||||
final employeeId = await sl<UserLocalDataSource>().getCachedEmployeeId();
|
||||
if (employeeId == null) {
|
||||
if (mounted) {
|
||||
@@ -198,12 +239,10 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare dates - if timed leave, use same date with time differences
|
||||
DateTime finalStartDate = fromDate!;
|
||||
DateTime finalEndDate = toDate!;
|
||||
|
||||
if (isTimedLeave) {
|
||||
// For timed leave, use the same date but with different times
|
||||
finalStartDate = DateTime(
|
||||
fromDate!.year,
|
||||
fromDate!.month,
|
||||
@@ -219,15 +258,12 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
toTime!.minute,
|
||||
);
|
||||
} else {
|
||||
// For regular leave, use dates at midnight
|
||||
finalStartDate = DateTime(fromDate!.year, fromDate!.month, fromDate!.day);
|
||||
finalEndDate = DateTime(toDate!.year, toDate!.month, toDate!.day);
|
||||
}
|
||||
|
||||
// Get vacation type value
|
||||
final typeValue = _getVacationTypeValue();
|
||||
|
||||
// Show loading indicator
|
||||
if (mounted) {
|
||||
showDialog(
|
||||
context: context,
|
||||
@@ -237,7 +273,6 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
}
|
||||
|
||||
try {
|
||||
// Create vacation request
|
||||
final vacationRequest = VacationRequest(
|
||||
employeeId: employeeId,
|
||||
startDate: finalStartDate,
|
||||
@@ -248,50 +283,48 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
|
||||
final result = await _createVacationUseCase(vacationRequest);
|
||||
|
||||
if (mounted) {
|
||||
Navigator.pop(context); // Close loading dialog
|
||||
if (!mounted) return;
|
||||
Navigator.pop(context);
|
||||
|
||||
result.fold(
|
||||
(failure) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(_getFailureMessage(failure)),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
},
|
||||
(response) {
|
||||
// Also save locally for UI display
|
||||
final leaveRequest = LeaveRequest(
|
||||
id: response.data?.id ?? DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
leaveType: leaveType,
|
||||
isTimedLeave: isTimedLeave,
|
||||
fromDate: fromDate!,
|
||||
toDate: toDate!,
|
||||
fromTime: fromTime!,
|
||||
toTime: toTime!,
|
||||
reason: reasonController.text,
|
||||
requestDate: DateTime.now(),
|
||||
status: "waiting", // Default status
|
||||
);
|
||||
_requestService.addLeaveRequest(leaveRequest);
|
||||
result.fold(
|
||||
(failure) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(_getFailureMessage(failure)),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
},
|
||||
(response) {
|
||||
final leaveRequest = LeaveRequest(
|
||||
id:
|
||||
response.data?.id ??
|
||||
DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
leaveType: leaveType,
|
||||
isTimedLeave: isTimedLeave,
|
||||
fromDate: fromDate!,
|
||||
toDate: toDate!,
|
||||
fromTime: fromTime!,
|
||||
toTime: toTime!,
|
||||
reason: reasonController.text,
|
||||
requestDate: DateTime.now(),
|
||||
status: "waiting",
|
||||
);
|
||||
_requestService.addLeaveRequest(leaveRequest);
|
||||
|
||||
// Show success message
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('تم إرسال طلب الأجازة بنجاح'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('تم إرسال طلب الأجازة بنجاح'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
|
||||
// Navigate back to the previous screen
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
}
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
Navigator.pop(context); // Close loading dialog
|
||||
Navigator.pop(context);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('حدث خطأ غير متوقع: $e'),
|
||||
@@ -305,12 +338,11 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: true, // ✅ IMPORTANT
|
||||
resizeToAvoidBottomInset: true,
|
||||
body: AppBackground(
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
// In your RequestLeaveScreen's build method, replace the SettingsBar with this:
|
||||
SettingsBar(
|
||||
selectedIndex: -1,
|
||||
onTap: (_) {},
|
||||
@@ -322,8 +354,6 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
],
|
||||
),
|
||||
|
||||
// Title
|
||||
// const SizedBox(height: 30),
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
@@ -331,7 +361,6 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Fixed alignment for "طلب أجازة"
|
||||
const Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: Text(
|
||||
@@ -343,11 +372,9 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(height: 10),
|
||||
//=============================
|
||||
// DROPDOWN: نوع الإجازة
|
||||
//=============================
|
||||
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: const Text(
|
||||
@@ -359,10 +386,9 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(height: 5),
|
||||
|
||||
// Modified dropdown with disabled state
|
||||
|
||||
Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Opacity(
|
||||
@@ -390,78 +416,77 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
],
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: _vacationTypes.isEmpty
|
||||
? const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
)
|
||||
: DropdownButton<int>(
|
||||
value: _selectedVacationTypeValue,
|
||||
icon: const Icon(
|
||||
Icons.keyboard_arrow_down_rounded,
|
||||
color: Colors.black,
|
||||
size: 28,
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 17,
|
||||
),
|
||||
isExpanded: true,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
child:
|
||||
_vacationTypes.isEmpty
|
||||
? const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child:
|
||||
CircularProgressIndicator(),
|
||||
),
|
||||
)
|
||||
: DropdownButton<int>(
|
||||
value: _selectedVacationTypeValue,
|
||||
icon: const Icon(
|
||||
Icons.keyboard_arrow_down_rounded,
|
||||
color: Colors.black,
|
||||
size: 28,
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 17,
|
||||
),
|
||||
isExpanded: true,
|
||||
onChanged: (value) {
|
||||
if (value == null) return;
|
||||
|
||||
setState(() {
|
||||
_selectedVacationTypeValue = value;
|
||||
final selectedType = _vacationTypes
|
||||
.firstWhere((t) => t.value == value);
|
||||
leaveType = _getArabicName(selectedType.name);
|
||||
// Set toggle based on selected value (TimeOff = 1)
|
||||
isTimedLeave = value == 1;
|
||||
_setSelectedVacationType(value);
|
||||
});
|
||||
}
|
||||
},
|
||||
items: _vacationTypes.map((type) {
|
||||
final arabicName = _getArabicName(type.name);
|
||||
return DropdownMenuItem<int>(
|
||||
value: type.value,
|
||||
child: Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text(arabicName),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
|
||||
// Sync toggle with selection
|
||||
if (value == 0 && !isTimedLeave) {
|
||||
_setTimedLeave(true);
|
||||
} else if (value != 0 &&
|
||||
isTimedLeave) {
|
||||
setState(
|
||||
() => isTimedLeave = false,
|
||||
);
|
||||
}
|
||||
},
|
||||
items:
|
||||
_vacationTypes.map((type) {
|
||||
final arabicName =
|
||||
_getArabicName(type.name);
|
||||
return DropdownMenuItem<int>(
|
||||
value: type.value,
|
||||
child: Directionality(
|
||||
textDirection:
|
||||
TextDirection.rtl,
|
||||
child: Align(
|
||||
alignment:
|
||||
Alignment
|
||||
.centerRight,
|
||||
child: Text(arabicName),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(height: 25),
|
||||
|
||||
//=============================
|
||||
// PERFECT CUSTOM TOGGLE (NEW)
|
||||
//=============================
|
||||
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isTimedLeave = !isTimedLeave;
|
||||
// Set leave type to TimeOff (value: 1) when toggle is ON
|
||||
if (isTimedLeave) {
|
||||
final timeOffType = _vacationTypes
|
||||
.firstWhere((t) => t.value == 1, orElse: () => _vacationTypes.first);
|
||||
_selectedVacationTypeValue = timeOffType.value;
|
||||
leaveType = _getArabicName(timeOffType.name);
|
||||
}
|
||||
});
|
||||
_setTimedLeave(!isTimedLeave);
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
// ---------- TOGGLE ----------
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 250),
|
||||
width: 75,
|
||||
@@ -472,12 +497,8 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
isTimedLeave
|
||||
? const Color(
|
||||
0xFF0A6B4A,
|
||||
) // ON green track
|
||||
: const Color(
|
||||
0xFF9E9E9E,
|
||||
), // OFF grey track
|
||||
? const Color(0xFF0A6B4A)
|
||||
: const Color(0xFF9E9E9E),
|
||||
borderRadius: BorderRadius.circular(40),
|
||||
),
|
||||
child: Align(
|
||||
@@ -492,8 +513,8 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
isTimedLeave
|
||||
? const Color(0xFF12BE85) // ON knob
|
||||
: Colors.white, // OFF knob
|
||||
? const Color(0xFF12BE85)
|
||||
: Colors.white,
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
@@ -506,10 +527,9 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(width: 14),
|
||||
|
||||
// ---------- Dot (ALWAYS visible) ----------
|
||||
|
||||
Container(
|
||||
width: 10,
|
||||
height: 10,
|
||||
@@ -518,20 +538,18 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(width: 6),
|
||||
|
||||
// ---------- Line (ALWAYS visible) ----------
|
||||
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 2,
|
||||
color: const Color(0xFF32C59A),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(width: 12),
|
||||
|
||||
// ---------- Label ----------
|
||||
|
||||
const Text(
|
||||
"إجازة زمنية",
|
||||
style: TextStyle(
|
||||
@@ -543,12 +561,9 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// =============================
|
||||
// DATE PICKER BOX
|
||||
// =============================
|
||||
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
@@ -565,10 +580,8 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end, // ALIGN RIGHT
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
// TEXT aligned right
|
||||
const Text(
|
||||
"فترة الإجازة",
|
||||
style: TextStyle(
|
||||
@@ -577,24 +590,17 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(width: 8),
|
||||
|
||||
// 🟢 YOUR CUSTOM SVG ICON
|
||||
SvgPicture.asset(
|
||||
"assets/images/calendar.svg", // <-- replace with your icon filename
|
||||
"assets/images/calendar.svg",
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: Color(
|
||||
0xFF007C46,
|
||||
), // Optional: match your green
|
||||
color: const Color(0xFF007C46),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// From date row
|
||||
|
||||
_dateRow(
|
||||
label: "من",
|
||||
date: fromDate!,
|
||||
@@ -603,10 +609,9 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
isTimedLeave ? null : () => pickDate(true),
|
||||
onTimeTap: () => pickTime(true),
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// To date row
|
||||
|
||||
_dateRow(
|
||||
label: "الى",
|
||||
date: toDate!,
|
||||
@@ -618,12 +623,9 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// =============================
|
||||
// REASON TEXTFIELD (Two Containers)
|
||||
// =============================
|
||||
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Directionality(
|
||||
@@ -638,21 +640,16 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// OUTER BORDER CONTAINER
|
||||
|
||||
Container(
|
||||
padding: const EdgeInsets.all(
|
||||
12,
|
||||
), // border thickness space
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Color(0xFF00FFAA), // green border
|
||||
color: const Color(0xFF00FFAA),
|
||||
width: 0.5,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
|
||||
// INNER TEXTFIELD CONTAINER
|
||||
child: Container(
|
||||
height: 70,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
@@ -663,35 +660,30 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
color: const Color(0xFFEAEAEA),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
// Added Directionality to fix text direction
|
||||
child: Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: TextField(
|
||||
controller: reasonController,
|
||||
maxLines: 5,
|
||||
textAlign:
|
||||
TextAlign
|
||||
.right, // Added this to align text to the right
|
||||
textAlign: TextAlign.right,
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText:
|
||||
"اكتب السبب", // Added placeholder text
|
||||
hintText: "اكتب السبب",
|
||||
hintStyle: TextStyle(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// CONFIRM BUTTON
|
||||
|
||||
Center(
|
||||
child: OnboardingButton(
|
||||
text: "تأكيد الطلب",
|
||||
backgroundColor: const Color(0xFFD1FEF0),
|
||||
textColor: Colors.black, // Changed to black
|
||||
onPressed: _saveLeaveRequest, // Call the save method
|
||||
textColor: Colors.black,
|
||||
onPressed: _saveLeaveRequest,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -706,9 +698,6 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// CUSTOM DATE ROW WIDGET
|
||||
// ===============================================================
|
||||
Widget _dateRow({
|
||||
required String label,
|
||||
required DateTime date,
|
||||
@@ -727,9 +716,6 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// -----------------------
|
||||
// DATE PART (can be disabled)
|
||||
// -----------------------
|
||||
Opacity(
|
||||
opacity: dateDisabled ? 0.45 : 1,
|
||||
child: IgnorePointer(
|
||||
@@ -757,9 +743,6 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
|
||||
const Spacer(),
|
||||
|
||||
// -----------------------
|
||||
// TIME PART (always active)
|
||||
// -----------------------
|
||||
GestureDetector(
|
||||
onTap: onTimeTap,
|
||||
child: Text(
|
||||
@@ -779,8 +762,11 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
// NOTE: DateTime.weekday is 1..7 (Mon..Sun)
|
||||
String _weekday(int day) {
|
||||
switch (day) {
|
||||
case 7:
|
||||
return "الأحد";
|
||||
case 1:
|
||||
return "الإثنين";
|
||||
case 2:
|
||||
@@ -793,8 +779,6 @@ class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
|
||||
return "الجمعة";
|
||||
case 6:
|
||||
return "السبت";
|
||||
case 7:
|
||||
return "الأحد";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user