TIF_E41222181/lib/feature_student/permission/presentation/permission_page.dart

338 lines
12 KiB
Dart

import 'package:absensi_qr/app_routes.dart';
import 'package:absensi_qr/constant/app_color.dart';
import 'package:absensi_qr/constant/app_font_style.dart';
import 'package:absensi_qr/constant/asset_constant.dart';
import 'package:absensi_qr/constant/spacing_size.dart';
import 'package:absensi_qr/core/helper/permission_helper.dart';
import 'package:absensi_qr/domain/enum/permission_status_enum.dart';
import 'package:absensi_qr/feature_student/permission/presentation/permission_controller.dart';
import 'package:absensi_qr/features/widgets/button_primary_widget.dart';
import 'package:absensi_qr/features/widgets/datepicker_input_withtitle.dart';
import 'package:absensi_qr/models/permission_model.dart';
import 'package:absensi_qr/utils/app_util.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
class PermissionPage extends StatelessWidget {
const PermissionPage({super.key});
@override
Widget build(BuildContext context) {
PermissionController controller = Get.find<PermissionController>();
return Scaffold(
backgroundColor: AppColor.backgroundColor,
appBar: AppBar(
backgroundColor: AppColor.backgroundColor,
elevation: 0,
centerTitle: false,
title: Text(
'Perizinan',
style: AppFontStyle.titleText.copyWith(color: Colors.black),
),
actions: [
IconButton(
onPressed: () => _showFilterBottomSheet(context, controller),
icon: const Icon(Icons.tune),
),
],
automaticallyImplyLeading: false,
),
body: RefreshIndicator(
onRefresh: () async {
await controller.getDataPermission();
},
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Container(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
// subtitle
Text('Daftar perizinan yang telah dibuat',
style: AppFontStyle.subTitleText),
// list card of permissions
SpacingSize.spacingBaseHeight,
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: TabBar(
controller: controller.tabController,
indicatorColor: AppColor.primaryColor,
labelColor: AppColor.primaryColor,
tabs: const [
Tab(text: 'Diproses'),
Tab(text: 'Disetujui'),
Tab(text: 'Ditolak'),
],
),
),
SpacingSize.spacingXSHeight,
Obx(() {
if (controller.isLoading.value) {
return Container(
width: double.infinity,
height: 150,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: const Center(child: CircularProgressIndicator()),
);
}
if (controller.filteredListPermission.isEmpty) {
return Container(
width: double.infinity,
height: 150,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: const Center(
child: Text('Data Kosong'),
),
);
}
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: controller.filteredListPermission.length,
itemBuilder: (context, index) {
final permission =
controller.filteredListPermission[index];
return Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: _cardPermissionContent(
context, permission, controller.nameOfStudent),
);
},
);
}),
Obx(() {
return controller.statusSelected.value ==
PermissionStatusEnum.proses
? ButtonPrimaryWidget(
borderRadius: 20,
title: "Buat",
callback: () {
Get.toNamed(AppRoutes.permissionForm);
})
: SizedBox.shrink();
}),
SpacingSize.spacingHugeHeight,
],
),
)),
),
);
}
void _showFilterBottomSheet(
BuildContext context, PermissionController controller) {
// init TextEditingControllers with current filter values
final startCtrl = TextEditingController(
text: DateFormat('dd/MM/yyyy').format(controller.filterStartDate.value),
);
final endCtrl = TextEditingController(
text: DateFormat('dd/MM/yyyy').format(controller.filterEndDate.value),
);
// local temp dates so we can cancel without affecting state
DateTime tempStart = controller.filterStartDate.value;
DateTime tempEnd = controller.filterEndDate.value;
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (_) => Padding(
padding: EdgeInsets.only(
left: 20,
right: 20,
top: 20,
bottom: MediaQuery.of(context).viewInsets.bottom + 24,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Filter Perizinan',
style: AppFontStyle.titleText.copyWith(fontSize: 16)),
SpacingSize.spacingBaseHeight,
DatepickerInputWithtitle(
title: 'Pilih Tanggal Mulai',
controller: startCtrl,
hintTxt: 'Pilih tanggal mulai',
lastDate: DateTime(DateTime.now().year + 5),
initialDate: tempStart,
),
SpacingSize.spacingBaseHeight,
DatepickerInputWithtitle(
title: 'Pilih Tanggal Selesai',
controller: endCtrl,
hintTxt: 'Pilih tanggal selesai',
lastDate: DateTime(DateTime.now().year + 5),
initialDate: tempEnd,
),
SpacingSize.spacingLGHeight,
ButtonPrimaryWidget(
borderRadius: 20,
title: 'Terapkan',
callback: () {
// parse dari text controller (format dd/MM/yyyy)
try {
final fmt = DateFormat('dd/MM/yyyy');
if (startCtrl.text.isNotEmpty) {
tempStart = fmt.parse(startCtrl.text);
}
if (endCtrl.text.isNotEmpty) {
tempEnd = fmt.parse(endCtrl.text);
}
controller.filterStartDate.value = tempStart;
controller.filterEndDate.value = tempEnd;
Navigator.pop(context);
controller.getDataPermission();
} catch (_) {}
},
),
SpacingSize.spacingLGHeight,
],
),
),
);
}
Widget _cardPermissionContent(
BuildContext context,
PermissionModel permission,
String nameOfStudent,
) {
final dateCreated = permission.createdAt ?? DateTime.now();
final formattedDate =
PermissionHelper.formatDisplayPermissionInfo(dateCreated);
final reason = permission.reason.name;
final status = permission.status.name;
// mapping status to color
final permissionStatusMap = {
PermissionStatusEnum.diterima: Colors.green,
PermissionStatusEnum.ditolak: Colors.red,
PermissionStatusEnum.proses: Colors.orange,
};
// permission icon path
final permissionIconPath = AssetConstant.getPermissionIconStatus(status);
return Container(
padding: const EdgeInsets.all(16),
width: double.infinity,
// height: 150,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: AppColor.primaryColor.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 5,
offset: const Offset(0, 1), // changes position of shadow
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(
permissionIconPath,
width: 40,
height: 40,
errorBuilder: (context, error, stackTrace) => Icon(
Icons.description,
size: 40,
color: AppColor.colorOutlineBoxinput,
),
),
SpacingSize.spacingSMWidth,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
reason,
style: AppFontStyle.primaryText
.copyWith(fontWeight: FontWeight.bold),
),
SpacingSize.spacingXSHeight,
// tanggal perizinan dibuat.
Text(
formattedDate,
style: AppFontStyle.subTitleText.copyWith(fontSize: 12),
),
],
)),
SpacingSize.spacingBaseWidth,
Text(
status,
style: AppFontStyle.subTitleText.copyWith(
color: permissionStatusMap[permission.status] ??
Colors.grey),
),
],
),
SpacingSize.spacingSMHeight,
Divider(color: AppColor.colorOutlineBoxinput),
SpacingSize.spacingXSHeight,
GestureDetector(
onTap: () {
// Handle tap event, e.g., navigate to detail page or show dialog
AppUtil.showPermissionDetailDialogStudent(
context,
permissionData: permission,
studentName: nameOfStudent,
onTap: () {
// handle to create new form permission.
Get.toNamed(AppRoutes.permissionForm);
},
);
},
child: Row(
children: [
Text(
'Lihat Detail Perizinan',
style: AppFontStyle.blueInfoText.copyWith(fontSize: 12),
),
SizedBox(width: 4),
Icon(
Icons.arrow_forward_ios,
size: 12,
color: AppColor.primaryColor,
)
],
),
),
],
));
}
}